Skip to content

Commit 9056116

Browse files
committed
feat: efm v2 support
# Conflicts: # aws_advanced_python_wrapper/plugin_service.py # aws_advanced_python_wrapper/utils/atomic.py # Conflicts: # docs/using-the-python-driver/UsingThePythonDriver.md
1 parent 409983d commit 9056116

17 files changed

+1137
-31
lines changed

aws_advanced_python_wrapper/host_monitoring_v2_plugin.py

Lines changed: 539 additions & 0 deletions
Large diffs are not rendered by default.

aws_advanced_python_wrapper/plugin_service.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@
7575
HostListProviderService, StaticHostListProvider)
7676
from aws_advanced_python_wrapper.host_monitoring_plugin import \
7777
HostMonitoringPluginFactory
78+
from aws_advanced_python_wrapper.host_monitoring_v2_plugin import \
79+
HostMonitoringV2PluginFactory
7880
from aws_advanced_python_wrapper.hostinfo import HostInfo, HostRole
7981
from aws_advanced_python_wrapper.iam_plugin import IamAuthPluginFactory
8082
from aws_advanced_python_wrapper.plugin import CanReleaseResources
@@ -755,6 +757,7 @@ class PluginManager(CanReleaseResources):
755757
"aws_secrets_manager": AwsSecretsManagerPluginFactory,
756758
"aurora_connection_tracker": AuroraConnectionTrackerPluginFactory,
757759
"host_monitoring": HostMonitoringPluginFactory,
760+
"host_monitoring_v2": HostMonitoringV2PluginFactory,
758761
"failover": FailoverPluginFactory,
759762
"read_write_splitting": ReadWriteSplittingPluginFactory,
760763
"fastest_response_strategy": FastestResponseStrategyPluginFactory,
@@ -783,6 +786,7 @@ class PluginManager(CanReleaseResources):
783786
ReadWriteSplittingPluginFactory: 300,
784787
FailoverPluginFactory: 400,
785788
HostMonitoringPluginFactory: 500,
789+
HostMonitoringV2PluginFactory: 510,
786790
BlueGreenPluginFactory: 550,
787791
FastestResponseStrategyPluginFactory: 600,
788792
IamAuthPluginFactory: 700,

aws_advanced_python_wrapper/resources/aws_advanced_python_wrapper_messages.properties

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,28 @@ HostMonitoringPlugin.ConfigurationNotSupported=[HostMonitoringPlugin] Aborting c
176176
HostMonitoringPlugin.UnableToIdentifyConnection=[HostMonitoringPlugin] Unable to identify the connected database instance: '{}', please ensure the correct host list provider is specified. The host list provider in use is: '{}'.
177177
HostMonitoringPlugin.UnavailableHost=[HostMonitoringPlugin] Host '{}' is unavailable.
178178

179+
HostMonitoringV2Plugin.ActivatedMonitoring=[HostMonitoringV2Plugin] Executing method '{}', monitoring is activated.
180+
HostMonitoringV2Plugin.ClusterEndpointHostInfo=[HostMonitoringV2Plugin] The HostInfo to monitor is associated with a cluster endpoint. The plugin will attempt to identify the connected database instance.
181+
HostMonitoringV2Plugin.ErrorIdentifyingConnection=[HostMonitoringV2Plugin] An error occurred while identifying the connection database instance: '{}'.
182+
HostMonitoringV2Plugin.MonitoringDeactivated=[HostMonitoringV2Plugin] Monitoring deactivated for method '{}'.
183+
HostMonitoringV2Plugin.ConnectionNone=[HostMonitoringV2Plugin] Attempted to execute method '{}' but the current connection is None.
184+
HostMonitoringV2Plugin.HostInfoNone=[HostMonitoringV2Plugin] Could not find HostInfo to monitor for the current connection.
185+
HostMonitoringV2Plugin.ConfigurationNotSupported=[HostMonitoringV2Plugin] Aborting connections from a separate thread is not supported for the detected driver dialect: '{}'. The EFM V2 plugin requires this feature to be supported.
186+
HostMonitoringV2Plugin.UnableToIdentifyConnection=[HostMonitoringV2Plugin] Unable to identify the connected database instance: '{}', please ensure the correct host list provider is specified. The host list provider in use is: '{}'.
187+
HostMonitorV2.ExceptionDuringMonitoringStop=[HostMonitorV2] Stopping monitoring after unhandled exception was thrown in monitoring thread for host '{}'. Exception: '{}'
188+
HostMonitorV2.MonitorIsStopped=[HostMonitorV2] Monitoring was already stopped for host '{}'.
189+
HostMonitorV2.StartMonitoringThreadNewContext=[HostMonitorV2] Start monitoring thread for checking new contexts for '{}'.
190+
HostMonitorV2.StopMonitoringThreadNewContext=[HostMonitorV2] Stop monitoring thread for checking new contexts for '{}'.
191+
HostMonitorV2.StartMonitoringThread=[HostMonitorV2] Start monitoring thread for '{}'.
192+
HostMonitorV2.OpeningMonitoringConnection=[HostMonitorV2] Opening a monitoring connection to '{}'
193+
HostMonitorV2.OpenedMonitoringConnection=[HostMonitorV2] Opened monitoring connection: '{}'
194+
HostMonitorV2.ExceptionAbortingConnection=[HostMonitorV2] Exception while aborting connection: '{}'
195+
HostMonitorV2.HostDead=[HostMonitorV2] Host '{}' is *dead*.
196+
HostMonitorV2.HostNotResponding=[HostMonitorV2] Host '{}' is not *responding* '{}'.
197+
HostMonitorV2.HostAlive=[HostMonitorV2] Host '{}' is *alive*.
198+
HostMonitorV2.StopMonitoringThread=[HostMonitorV2] Stop monitoring thread for '{}'.
199+
MonitorServiceV2.ExceptionAbortingConnection=[MonitorServiceV2] Exception during aborting connection: '{}'
200+
179201
HostSelector.NoEligibleHost=[HostSelector] No Eligible Hosts Found.
180202
HostSelector.NoHostsMatchingRole=[HostSelector] No hosts were found matching the requested role: '{}'.
181203

@@ -193,15 +215,15 @@ LimitlessPlugin.UnsupportedDialectOrDatabase=[LimitlessPlugin] Unsupported diale
193215

194216
LimitlessQueryHelper.UnsupportedDialectOrDatabase=[LimitlessQueryHelper] Unsupported dialect '{}' encountered. Please ensure JDBC connection parameters are correct, and refer to the documentation to ensure that the connecting database is compatible with the Limitless Connection Plugin.
195217

196-
LimitlessRouterMonitor.errorDuringMonitoringStop=[LimitlessRouterMonitor] Stopping monitoring after unhandled error was thrown in Limitless Router Monitoring thread for node {}. Error: {}
197-
LimitlessRouterMonitor.InterruptedErrorDuringMonitoring=[LimitlessRouterMonitor] Limitless Router Monitoring thread for node {} was interrupted.
218+
LimitlessRouterMonitor.errorDuringMonitoringStop=[LimitlessRouterMonitor] Stopping monitoring after unhandled error was thrown in Limitless Router Monitoring thread for host {}. Error: {}
219+
LimitlessRouterMonitor.InterruptedErrorDuringMonitoring=[LimitlessRouterMonitor] Limitless Router Monitoring thread for host {} was interrupted.
198220
LimitlessRouterMonitor.InvalidQuery=[LimitlessRouterMonitor] Limitless Connection Plugin has encountered an error obtaining Limitless Router endpoints. Please ensure that you are connecting to an Aurora Limitless Database Shard Group Endpoint URL.
199221
LimitlessRouterMonitor.InvalidRouterLoad=[LimitlessRouterMonitor] Invalid load metric value of '{}' from the transaction router query aurora_limitless_router_endpoints() for transaction router '{}'. The load metric value must be a decimal value between 0 and 1. Host weight be assigned a default weight of 1.
200222
LimitlessRouterMonitor.GetNetworkTimeoutError=[LimitlessRouterMonitor] An error occurred while getting the connection network timeout: {}
201223
LimitlessRouterMonitor.OpeningConnection=[LimitlessRouterMonitor] Opening Limitless Router Monitor connection to '{}'.
202224
LimitlessRouterMonitor.OpenedConnection=[LimitlessRouterMonitor] Opened Limitless Router Monitor connection: {}.
203-
LimitlessRouterMonitor.Running=[LimitlessRouterMonitor] Limitless Router Monitor thread running on node {}.
204-
LimitlessRouterMonitor.Stopped=[LimitlessRouterMonitor] Limitless Router Monitor thread stopped on node {}.
225+
LimitlessRouterMonitor.Running=[LimitlessRouterMonitor] Limitless Router Monitor thread running on host {}.
226+
LimitlessRouterMonitor.Stopped=[LimitlessRouterMonitor] Limitless Router Monitor thread stopped on host {}.
205227

206228
LimitlessRouterService.ConnectWithHost=[LimitlessRouterService] Connecting to host {}.
207229
LimitlessRouterService.ErrorClosingMonitor=[LimitlessRouterService] An error occurred while closing Limitless Router Monitor: {}

aws_advanced_python_wrapper/utils/atomic.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
# limitations under the License.
1414

1515
from threading import Lock
16+
from typing import Generic, TypeVar
17+
18+
T = TypeVar('T')
1619

1720

1821
class AtomicInt:
@@ -59,3 +62,31 @@ def compare_and_set(self, expected_value: int, new_value: int) -> bool:
5962
self._value = new_value
6063
return True
6164
return False
65+
66+
67+
class AtomicBoolean:
68+
def __init__(self, initial_value: bool):
69+
self._value: bool = initial_value
70+
self._lock: Lock = Lock()
71+
72+
def get(self) -> bool:
73+
with self._lock:
74+
return self._value
75+
76+
def set(self, value: bool) -> None:
77+
with self._lock:
78+
self._value = value
79+
80+
81+
class AtomicReference(Generic[T]):
82+
def __init__(self, initial_value: T):
83+
self._value: T = initial_value
84+
self._lock: Lock = Lock()
85+
86+
def get(self) -> T:
87+
with self._lock:
88+
return self._value
89+
90+
def set(self, new_value: T) -> None:
91+
with self._lock:
92+
self._value = new_value

aws_advanced_python_wrapper/utils/properties.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ def set(self, props: Properties, value: Any):
7373

7474

7575
class WrapperProperties:
76-
DEFAULT_PLUGINS = "aurora_connection_tracker,failover,host_monitoring"
76+
DEFAULT_PLUGINS = "aurora_connection_tracker,failover,host_monitoring_v2"
7777
_DEFAULT_TOKEN_EXPIRATION_SEC = 15 * 60
7878

7979
PROFILE_NAME = WrapperProperty("profile_name", "Driver configuration profile name", None)

docs/using-the-python-driver/UsingThePythonDriver.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ The AWS Advanced Python Driver has several built-in plugins that are available t
6464
| Plugin name | Plugin Code | Database Compatibility | Description | Additional Required Dependencies |
6565
|--------------------------------------------------------------------------------------------------------|-----------------------------|--------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------|
6666
| [Failover Connection Plugin](./using-plugins/UsingTheFailoverPlugin.md) | `failover` | Aurora | Enables the failover functionality supported by Amazon Aurora clusters. Prevents opening a wrong connection to an old writer host dues to stale DNS after failover event. This plugin is enabled by default. | None |
67-
| [Host Monitoring Connection Plugin](./using-plugins/UsingTheHostMonitoringPlugin.md) | `host_monitoring` | Aurora | Enables enhanced host connection failure monitoring, allowing faster failure detection rates. This plugin is enabled by default. | None |
67+
| [Host Monitoring Connection Plugin](./using-plugins/UsingTheHostMonitoringPlugin.md) | `host_monitoring_v2` or `host_monitoring` | Aurora | Enables enhanced host connection failure monitoring, allowing faster failure detection rates. This plugin is enabled by default. | None |
6868
| [IAM Authentication Connection Plugin](./using-plugins/UsingTheIamAuthenticationPlugin.md) | `iam` | Any database | Enables users to connect to their Amazon Aurora clusters using AWS Identity and Access Management (IAM). | [Boto3 - AWS SDK for Python](https://aws.amazon.com/sdk-for-python/) |
6969
| [AWS Secrets Manager Connection Plugin](./using-plugins/UsingTheAwsSecretsManagerPlugin.md) | `aws_secrets_manager` | Any database | Enables fetching database credentials from the AWS Secrets Manager service. | [Boto3 - AWS SDK for Python](https://aws.amazon.com/sdk-for-python/) |
7070
| [Federated Authentication Connection Plugin](./using-plugins/UsingTheFederatedAuthenticationPlugin.md) | `federated_auth` | Any database | Enables users to authenticate via Federated Identity and then database access via IAM. | [Boto3 - AWS SDK for Python](https://aws.amazon.com/sdk-for-python/) |

docs/using-the-python-driver/using-plugins/UsingTheFastestResponseStrategyPlugin.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ The plugin can be loaded by adding the plugin code `fastest_response_strategy` t
1313
1414
```python
1515
params = {
16-
"plugins": "read_write_splitting,fastest_response_strategy,failover,host_monitoring",
16+
"plugins": "read_write_splitting,fastest_response_strategy,failover,host_monitoring_v2",
1717
"reader_response_strategy": "fastest_response"
1818
# Add other connection properties below...
1919
}

docs/using-the-python-driver/using-plugins/UsingTheHostMonitoringPlugin.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,19 @@ conn = AwsWrapperConnection.connect(
7979
> We recommend you either disable the Host Monitoring Connection Plugin or avoid using RDS Proxy endpoints when the Host Monitoring Connection Plugin is active.
8080
>
8181
> Although using RDS Proxy endpoints with the AWS Advanced Python Driver with Enhanced Failure Monitoring doesn't cause any critical issues, we don't recommend this approach. The main reason is that RDS Proxy transparently re-routes requests to a single database instance. RDS Proxy decides which database instance is used based on many criteria (on a per-request basis). Switching between different instances makes the Host Monitoring Connection Plugin useless in terms of instance health monitoring because the plugin will be unable to identify which instance it's connected to, and which one it's monitoring. This could result in false positive failure detections. At the same time, the plugin will still proactively monitor network connectivity to RDS Proxy endpoints and report outages back to a user application if they occur.
82+
83+
# Host Monitoring Plugin v2
84+
85+
Host Monitoring Plugin v2, also known as `host_monitoring_v2`, is an alternative implementation of enhanced failure monitoring and it is functionally equivalent to the Host Monitoring Plugin described above. Both plugins share the same set of [configuration parameters](#enhanced-failure-monitoring-parameters). The `host_monitoring_v2` plugin is designed to be a drop-in replacement for the `host_monitoring` plugin.
86+
The `host_monitoring_v2` plugin can be used in any scenario where the `host_monitoring` plugin is mentioned. This plugin is enabled by default. The original EFM plugin can still be used by specifying `host_monitoring` in the `plugins` parameter.
87+
88+
> [!NOTE]\
89+
> Since these two plugins are separate plugins, users may decide to use them together with a single connection. While this should not have any negative side effects, it is not recommended. It is recommended to use either the `host_monitoring_v2` plugin, or the `host_monitoring` plugin where it's needed.
90+
91+
92+
The `host_monitoring_v2` plugin is designed to address [some of the issues](https://github.com/aws/aws-advanced-jdbc-wrapper/issues/675) that have been reported by multiple users. The following changes have been made:
93+
- Used weak pointers to ease garbage collection
94+
- Split monitoring logic into two separate threads to increase overall monitoring stability
95+
- Reviewed locks for monitoring context
96+
- Reviewed and redesigned stopping of idle monitoring threads
97+
- Reviewed and simplified monitoring logic

docs/using-the-python-driver/using-plugins/UsingTheReadWriteSplittingPlugin.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ The Read/Write Splitting Plugin is not loaded by default. To load the plugin, in
88

99
```python
1010
params = {
11-
"plugins": "read_write_splitting,failover,host_monitoring",
11+
"plugins": "read_write_splitting,failover,host_monitoring_v2",
1212
# Add other connection properties below...
1313
}
1414

tests/integration/container/test_aurora_failover.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ def test_fail_from_writer_to_new_writer_fail_on_connection_bound_object_invocati
116116
assert aurora_utility.is_db_instance_writer(current_connection_id) is True
117117
assert current_connection_id != initial_writer_id
118118

119+
@pytest.mark.parametrize("plugins", ["failover,host_monitoring", "failover,host_monitoring_v2"])
119120
@enable_on_features([TestEnvironmentFeatures.NETWORK_OUTAGES_ENABLED,
120121
TestEnvironmentFeatures.ABORT_CONNECTION_SUPPORTED])
121122
def test_fail_from_reader_to_writer(
@@ -124,12 +125,13 @@ def test_fail_from_reader_to_writer(
124125
test_driver: TestDriver,
125126
conn_utils,
126127
proxied_props,
127-
aurora_utility):
128+
aurora_utility,
129+
plugins):
128130
target_driver_connect = DriverHelper.get_connect_func(test_driver)
129131
reader: TestInstanceInfo = test_environment.get_proxy_instances()[1]
130132
writer_id: str = test_environment.get_proxy_writer().get_instance_id()
131133

132-
proxied_props["plugins"] = "failover,host_monitoring"
134+
proxied_props["plugins"] = plugins
133135
with AwsWrapperConnection.connect(
134136
target_driver_connect,
135137
**conn_utils.get_proxy_connect_params(reader.get_host()),

0 commit comments

Comments
 (0)