From 3f8f6cab40b9785f622751a87c0cb7b5f6da4f74 Mon Sep 17 00:00:00 2001 From: Sophia Chu <112967780+sophia-bq@users.noreply.github.com> Date: Fri, 22 Nov 2024 11:13:55 -0800 Subject: [PATCH] chore: refactor static setConnectionProvider method (#330) --- common/lib/aws_client.ts | 3 +- common/lib/connection_provider_manager.ts | 39 +------------------ common/lib/wrapper_property.ts | 7 ++++ docs/development-guide/Pipelines.md | 4 +- .../UsingTheReadWriteSplittingPlugin.md | 12 +++--- ..._pool_password_warning_postgres_example.ts | 18 ++++----- ...ion_pool_password_warning_mysql_example.ts | 18 ++++----- ...ternal_connection_pooling_mysql_example.ts | 30 +++++++------- ...nal_connection_pooling_postgres_example.ts | 30 +++++++------- .../container/tests/autoscaling.test.ts | 19 +++++---- .../tests/read_write_splitting.test.ts | 29 +++++++------- .../read_write_splitting_performance.test.ts | 17 ++++---- .../internal_pool_connection_provider.test.ts | 1 - tests/unit/read_write_splitting.test.ts | 4 +- 14 files changed, 98 insertions(+), 133 deletions(-) diff --git a/common/lib/aws_client.ts b/common/lib/aws_client.ts index 39c08822..58e32245 100644 --- a/common/lib/aws_client.ts +++ b/common/lib/aws_client.ts @@ -30,6 +30,7 @@ import { ConnectionProviderManager } from "./connection_provider_manager"; import { DefaultTelemetryFactory } from "./utils/telemetry/default_telemetry_factory"; import { TelemetryFactory } from "./utils/telemetry/telemetry_factory"; import { DriverDialect } from "./driver_dialect/driver_dialect"; +import { WrapperProperties } from "./wrapper_property"; export abstract class AwsClient extends EventEmitter { private _defaultPort: number = -1; @@ -63,7 +64,7 @@ export abstract class AwsClient extends EventEmitter { this.pluginManager = new PluginManager( container, this.properties, - new ConnectionProviderManager(new DriverConnectionProvider(), null), + new ConnectionProviderManager(new DriverConnectionProvider(), WrapperProperties.CONNECTION_PROVIDER.get(this.properties)), this.telemetryFactory ); } diff --git a/common/lib/connection_provider_manager.ts b/common/lib/connection_provider_manager.ts index e04ab8a1..f957a3ed 100644 --- a/common/lib/connection_provider_manager.ts +++ b/common/lib/connection_provider_manager.ts @@ -17,10 +17,8 @@ import { ConnectionProvider } from "./connection_provider"; import { HostRole } from "./host_role"; import { HostInfo } from "./host_info"; -import { CanReleaseResources } from "./can_release_resources"; export class ConnectionProviderManager { - private static connProvider: ConnectionProvider | null = null; private readonly defaultProvider: ConnectionProvider; private readonly effectiveProvider: ConnectionProvider | null; @@ -29,19 +27,11 @@ export class ConnectionProviderManager { this.effectiveProvider = effectiveProvider; } - static setConnectionProvider(connProvider: ConnectionProvider) { - ConnectionProviderManager.connProvider = connProvider; - } - getConnectionProvider(hostInfo: HostInfo | null, props: Map): ConnectionProvider { if (hostInfo === null) { return this.defaultProvider; } - if (ConnectionProviderManager.connProvider?.acceptsUrl(hostInfo, props)) { - return ConnectionProviderManager.connProvider; - } - if (this.effectiveProvider && this.effectiveProvider.acceptsUrl(hostInfo, props)) { return this.effectiveProvider; } @@ -50,22 +40,11 @@ export class ConnectionProviderManager { } acceptsStrategy(role: HostRole, strategy: string) { - return ( - ConnectionProviderManager.connProvider?.acceptsStrategy(role, strategy) || - this.effectiveProvider?.acceptsStrategy(role, strategy) || - this.defaultProvider.acceptsStrategy(role, strategy) - ); + return this.effectiveProvider?.acceptsStrategy(role, strategy) || this.defaultProvider.acceptsStrategy(role, strategy); } getHostInfoByStrategy(hosts: HostInfo[], role: HostRole, strategy: string, props: Map) { let host; - if (ConnectionProviderManager.connProvider?.acceptsStrategy(role, strategy)) { - try { - host = ConnectionProviderManager.connProvider.getHostInfoByStrategy(hosts, role, strategy, props); - } catch { - // Ignore and try with other providers. - } - } if (this.effectiveProvider?.acceptsStrategy(role, strategy)) { try { @@ -81,20 +60,4 @@ export class ConnectionProviderManager { return host; } - - static async releaseResources(): Promise { - if (ConnectionProviderManager.connProvider !== null) { - if (this.implementsCanReleaseResources(ConnectionProviderManager.connProvider)) { - await ConnectionProviderManager.connProvider.releaseResources(); - } - } - } - - private static implementsCanReleaseResources(connectionProvider: any): connectionProvider is CanReleaseResources { - return connectionProvider.releaseResources !== undefined; - } - - static resetProvider() { - this.connProvider = null; - } } diff --git a/common/lib/wrapper_property.ts b/common/lib/wrapper_property.ts index 4d6090d3..8e617a84 100644 --- a/common/lib/wrapper_property.ts +++ b/common/lib/wrapper_property.ts @@ -14,6 +14,8 @@ limitations under the License. */ +import { ConnectionProvider } from "./connection_provider"; + export class WrapperProperty { name: string; description: string; @@ -63,6 +65,11 @@ export class WrapperProperties { static readonly HOST = new WrapperProperty("host", "Database host", null); static readonly DIALECT = new WrapperProperty("dialect", "A unique identifier for the supported database dialect.", null); + static readonly CONNECTION_PROVIDER = new WrapperProperty( + "connectionProvider", + "The connection provider used to create connections.", + null + ); static readonly INTERNAL_QUERY_TIMEOUT = new WrapperProperty( "mysqlQueryTimeout", diff --git a/docs/development-guide/Pipelines.md b/docs/development-guide/Pipelines.md index 575ca2e1..1bb56943 100644 --- a/docs/development-guide/Pipelines.md +++ b/docs/development-guide/Pipelines.md @@ -22,7 +22,7 @@ For information on how to subscribe to these pipelines, please see the documenta ## Connect Pipeline -The connect pipeline performs any additional setup or post connection steps required to establish a connection. By default, the connect pipeline will establish connections using the `DriverConnectionProvider` class. If you would like to use a non-default `ConnectionProvider` to create connections, you can do so by calling `ConnectionProviderManager.setConnectionProvider(new CustomConnectionProvider())`. +The connect pipeline performs any additional setup or post connection steps required to establish a connection. By default, the connect pipeline will establish connections using the `DriverConnectionProvider` class. If you would like to use a non-default `ConnectionProvider` to create connections, you can do so by setting the connection property `connectionProvider: new CustomConnectionProvider()`. The wrapper provides a custom connection provider called `InternalPooledConnectionProvider`. This provider creates pooled clients and are intended to be used with the Read/Write Splitting plugin. To learn more about this provider, see the internal connection pool section in [UsingTheReadWriteSplittingPlugin.md](https://github.com/aws/aws-advanced-nodejs-wrapper/blob/main/docs/using-the-nodejs-wrapper/using-plugins/UsingTheReadWriteSplittingPlugin.md). @@ -32,7 +32,7 @@ An example would be the IAM connection plugin. The IAM connection plugin generat ## Force Connect Pipeline -The force connect pipeline is similar to the connect pipeline except that it will use the default `DriverConnectionProvider` class to establish connections regardless of whether a non-default `ConnectionProvider` has been requested via `ConnectionProviderManager.setConnectionProvider(new CustomConnectionProvider())`. For most plugins, the connect and force connect implementation will be equivalent. +The force connect pipeline is similar to the connect pipeline except that it will use the default `DriverConnectionProvider` class to establish connections regardless of whether a non-default `ConnectionProvider` has been requested via the `connectionProvider` connection property. For most plugins, the connect and force connect implementation will be equivalent. ## Execute Pipeline diff --git a/docs/using-the-nodejs-wrapper/using-plugins/UsingTheReadWriteSplittingPlugin.md b/docs/using-the-nodejs-wrapper/using-plugins/UsingTheReadWriteSplittingPlugin.md index 36339ca6..2455559d 100644 --- a/docs/using-the-nodejs-wrapper/using-plugins/UsingTheReadWriteSplittingPlugin.md +++ b/docs/using-the-nodejs-wrapper/using-plugins/UsingTheReadWriteSplittingPlugin.md @@ -37,7 +37,7 @@ The Read/Write Splitting Plugin is not currently supported for non-Aurora cluste ## Internal Connection Pooling > [!WARNING] -> If internal connection pools are enabled, database passwords may not be verified with every connection request. The initial connection request for each database instance in the cluster will verify the password, but subsequent requests may return a cached pool connection without re-verifying the password. This behavior is inherent to the nature of connection pools in general and not a bug with the wrapper. `await ConnectionProviderManager.releaseResources()` can be called to close all pools and remove all cached pool connections. See [Internal Connection Pool Password Warning Example for Postgres](../../../examples/aws_driver_example/aws_interal_connection_pool_password_warning_postgres_example.ts) and [Internal Connection Pool Password Warning Example for MySQL](../../../examples/aws_driver_example/aws_internal_connection_pool_password_warning_mysql_example.ts) +> If internal connection pools are enabled, database passwords may not be verified with every connection request. The initial connection request for each database instance in the cluster will verify the password, but subsequent requests may return a cached pool connection without re-verifying the password. This behavior is inherent to the nature of connection pools in general and not a bug with the wrapper. `await .releaseResources()` can be called to close all pools and remove all cached pool connections. See [Internal Connection Pool Password Warning Example for Postgres](../../../examples/aws_driver_example/aws_interal_connection_pool_password_warning_postgres_example.ts) and [Internal Connection Pool Password Warning Example for MySQL](../../../examples/aws_driver_example/aws_internal_connection_pool_password_warning_mysql_example.ts) Whenever `await setReadOnly(true)` is first called on a `AwsClient` object, the read/write plugin will internally open a new physical connection to a reader. After this first call, the physical reader connection will be cached for the given `AwsClient`. Future calls to `setReadOnly` on the same `AwsClient` object will not require opening a new physical connection. However, calling `await setReadOnly(true)` for the first time on a new `AwsClient` object will require the plugin to establish another new physical connection to a reader. If your application frequently calls `setReadOnly`, you can enable internal connection pooling to improve performance. When enabled, the wrapper driver will maintain an internal connection pool for each instance in the cluster. This allows the read/write splitting plugin to reuse connections that were established by `setReadOnly` calls on previous `AwsClient` objects. @@ -91,22 +91,22 @@ const myPoolKeyFunc: InternalPoolMapping = { }; const poolConfig = new AwsPoolConfig({ maxConnections: 10, idleTimeoutMillis: 10000 }); const provider = new InternalPooledConnectionProvider(poolConfig, myPoolKeyFunc); -ConnectionProviderManager.setConnectionProvider(provider); +props.set("connectionProvider", provider); ``` > [!WARNING] -> If you do not include the username in your InternalPoolMapping function, connection pools may be shared between different users. As a result, an initial connection established with a privileged user may be returned to a connection request with a lower-privilege user without re-verifying credentials. This behavior is inherent to the nature of connection pools in general and not a bug with the driver. `await ConnectionProviderManager.releaseResources()` can be called to close all pools and remove all cached pool connections. +> If you do not include the username in your InternalPoolMapping function, connection pools may be shared between different users. As a result, an initial connection established with a privileged user may be returned to a connection request with a lower-privilege user without re-verifying credentials. This behavior is inherent to the nature of connection pools in general and not a bug with the driver. `await provider.releaseResources()` can be called to close all pools and remove all cached pool connections. -2. Call `ConnectionProviderManager.setConnectionProvider()`, passing in the `InternalPoolConnectionProvider` you created in Step 1. +2. Set the `connectionProvider` connection property, passing in the `InternalPoolConnectionProvider` you created in Step 1. 3. By default, the read/write plugin randomly selects a reader instance the first time that `await setReadOnly(true)` is called. If you would like the plugin to select a reader based on a different selection strategy, please see the [Reader Selection](#reader-selection) section for more information. 4. Continue as normal: create connections and use them as needed. -5. When you are finished using all connections, call `await ConnectionProviderManager.releaseResources()`. +5. When you are finished using all connections, call `await provider.releaseResources()`. > [!IMPORTANT] -> You must call `await ConnectionProviderManager.releaseResources()` to close the internal connection pools when you are finished using all connections. Unless `await ConnectionProviderManager.releaseResources()` is called, the wrapper driver will keep the pools open so that they can be shared between connections. +> You must call `await provider.releaseResources()` to close the internal connection pools when you are finished using all connections. Unless `await ConnectionProviderManager.releaseResources()` is called, the wrapper driver will keep the pools open so that they can be shared between connections. ### Reader Selection diff --git a/examples/aws_driver_example/aws_interal_connection_pool_password_warning_postgres_example.ts b/examples/aws_driver_example/aws_interal_connection_pool_password_warning_postgres_example.ts index 81206dd2..d242b83d 100644 --- a/examples/aws_driver_example/aws_interal_connection_pool_password_warning_postgres_example.ts +++ b/examples/aws_driver_example/aws_interal_connection_pool_password_warning_postgres_example.ts @@ -26,22 +26,22 @@ const wrongPassword = "wrong_password"; const database = "database"; const port = 5432; +/** + * Configure read-write splitting to use internal connection pools (the pool config and mapping + * parameters are optional, see UsingTheReadWriteSplittingPlugin.md for more info). + */ +const provider = new InternalPooledConnectionProvider(); + const client = new AwsPGClient({ host: postgresHost, port: port, user: username, password: correctPassword, database: database, - plugins: "readWriteSplitting" + plugins: "readWriteSplitting", + connectionProvider: provider }); -/** - * Configure read-write splitting to use internal connection pools (the pool config and mapping - * parameters are optional, see UsingTheReadWriteSplittingPlugin.md for more info). - */ -const provider = new InternalPooledConnectionProvider(); -ConnectionProviderManager.setConnectionProvider(provider); - // Create an internal connection pool with the correct password try { await client.connect(); @@ -72,7 +72,7 @@ try { await newClient.end(); } // Closes all pools and removes all cached pool connections. -await ConnectionProviderManager.releaseResources(); +await provider.releaseResources(); const newClient2 = new AwsPGClient({ host: postgresHost, diff --git a/examples/aws_driver_example/aws_internal_connection_pool_password_warning_mysql_example.ts b/examples/aws_driver_example/aws_internal_connection_pool_password_warning_mysql_example.ts index d13a2fa1..df353d50 100644 --- a/examples/aws_driver_example/aws_internal_connection_pool_password_warning_mysql_example.ts +++ b/examples/aws_driver_example/aws_internal_connection_pool_password_warning_mysql_example.ts @@ -26,22 +26,22 @@ const wrongPassword = "wrong_password"; const database = "database"; const port = 3306; +/** + * Configure read-write splitting to use internal connection pools (the pool config and mapping + * parameters are optional, see UsingTheReadWriteSplittingPlugin.md for more info). + */ +const provider = new InternalPooledConnectionProvider(); + const client = new AwsMySQLClient({ host: mysqlHost, port: port, user: username, password: correctPassword, database: database, - plugins: "readWriteSplitting" + plugins: "readWriteSplitting", + connectionProvider: provider }); -/** - * Configure read-write splitting to use internal connection pools (the pool config and mapping - * parameters are optional, see UsingTheReadWriteSplittingPlugin.md for more info). - */ -const provider = new InternalPooledConnectionProvider(); -ConnectionProviderManager.setConnectionProvider(provider); - // Create an internal connection pool with the correct password try { await client.connect(); @@ -72,7 +72,7 @@ try { await newClient.end(); } // Closes all pools and removes all cached pool connections. -await ConnectionProviderManager.releaseResources(); +await provider.releaseResources(); const newClient2 = new AwsMySQLClient({ host: mysqlHost, diff --git a/examples/aws_driver_example/aws_internal_connection_pooling_mysql_example.ts b/examples/aws_driver_example/aws_internal_connection_pooling_mysql_example.ts index 47d2e79a..30e64655 100644 --- a/examples/aws_driver_example/aws_internal_connection_pooling_mysql_example.ts +++ b/examples/aws_driver_example/aws_internal_connection_pooling_mysql_example.ts @@ -29,19 +29,6 @@ const password = "employees"; const database = "database"; const port = 3306; -const client = new AwsMySQLClient({ - // Configure connection parameters. Enable readWriteSplitting, failover, and efm plugins. - host: mysqlHost, - port: port, - user: username, - password: password, - database: database, - plugins: "readWriteSplitting,failover,efm", - - // Optional: PoolKey property value used in internal connection pools - dbUser: "john_smith" -}); - /** * Optional method: only use if configured to use internal connection pools. * The configuration in these methods are only examples - you can configure as you need in your own code. @@ -59,7 +46,20 @@ const myKeyFunc: InternalPoolMapping = { */ const poolConfig = new AwsPoolConfig({ maxConnections: 10, maxIdleConnections: 10, idleTimeoutMillis: 10000 }); const provider = new InternalPooledConnectionProvider(poolConfig, myKeyFunc); -ConnectionProviderManager.setConnectionProvider(provider); + +const client = new AwsMySQLClient({ + // Configure connection parameters. Enable readWriteSplitting, failover, and efm plugins. + host: mysqlHost, + port: port, + user: username, + password: password, + database: database, + plugins: "readWriteSplitting,failover,efm", + + // Optional: PoolKey property value and connection provider used in internal connection pools. + connectionProvider: provider, + dbUser: "john_smith" +}); // Setup Step: Open connection and create tables - uncomment this section to create table and test values. /* try { @@ -108,7 +108,7 @@ try { await client.end(); // If configured to use internal connection pools, close them here. - await ConnectionProviderManager.releaseResources(); + await provider.releaseResources(); } async function setInitialSessionSettings(client: AwsMySQLClient) { diff --git a/examples/aws_driver_example/aws_internal_connection_pooling_postgres_example.ts b/examples/aws_driver_example/aws_internal_connection_pooling_postgres_example.ts index c058acc7..1bb4a768 100644 --- a/examples/aws_driver_example/aws_internal_connection_pooling_postgres_example.ts +++ b/examples/aws_driver_example/aws_internal_connection_pooling_postgres_example.ts @@ -29,19 +29,6 @@ const password = "employees"; const database = "database"; const port = 5432; -const client = new AwsPGClient({ - // Configure connection parameters. Enable readWriteSplitting, failover, and efm plugins. - host: postgresHost, - port: port, - user: username, - password: password, - database: database, - plugins: "readWriteSplitting,failover,efm", - - // Optional: PoolKey property value used in internal connection pools. - dbUser: "john_smith" -}); - /** * Optional methods: only required if configured to use internal connection pools. * The configuration in these methods are only examples - you can configure as you needed in your own code. @@ -59,7 +46,20 @@ const myPoolKeyFunc: InternalPoolMapping = { */ const poolConfig = new AwsPoolConfig({ maxConnections: 10, maxIdleConnections: 10, idleTimeoutMillis: 10000, allowExitOnIdle: true }); const provider = new InternalPooledConnectionProvider(poolConfig, myPoolKeyFunc); -ConnectionProviderManager.setConnectionProvider(provider); + +const client = new AwsPGClient({ + // Configure connection parameters. Enable readWriteSplitting, failover, and efm plugins. + host: postgresHost, + port: port, + user: username, + password: password, + database: database, + plugins: "readWriteSplitting,failover,efm", + + // Optional: PoolKey property value and connection provider used in internal connection pools. + connectionProvider: provider, + dbUser: "john_smith" +}); // Setup Step: Open connection and create tables - uncomment this section to create table and test values. /* try { @@ -108,7 +108,7 @@ try { await client.end(); // If configured to use internal connection pools, close them here. - await ConnectionProviderManager.releaseResources(); + await provider.releaseResources(); } async function setInitialSessionSettings(client: AwsPGClient) { diff --git a/tests/integration/container/tests/autoscaling.test.ts b/tests/integration/container/tests/autoscaling.test.ts index f1f6c1b9..3e6cd0a8 100644 --- a/tests/integration/container/tests/autoscaling.test.ts +++ b/tests/integration/container/tests/autoscaling.test.ts @@ -43,7 +43,7 @@ let newInstanceClient: any; let auroraTestUtility: AuroraTestUtility; let provider: InternalPooledConnectionProvider | null; -async function initDefaultConfig(host: string, port: number): Promise { +async function initDefaultConfig(host: string, port: number, provider: InternalPooledConnectionProvider): Promise { let config: any = { user: env.databaseInfo.username, host: host, @@ -51,6 +51,7 @@ async function initDefaultConfig(host: string, port: number): Promise { password: env.databaseInfo.password, port: port, plugins: "readWriteSplitting", + connectionProvider: provider, enableTelemetry: true, telemetryTracesBackend: "OTLP", telemetryMetricsBackend: "OTLP", @@ -61,7 +62,7 @@ async function initDefaultConfig(host: string, port: number): Promise { return config; } -async function initConfigWithFailover(host: string, port: number): Promise { +async function initConfigWithFailover(host: string, port: number, provider: InternalPooledConnectionProvider): Promise { let config: any = { user: env.databaseInfo.username, host: host, @@ -69,6 +70,7 @@ async function initConfigWithFailover(host: string, port: number): Promise password: env.databaseInfo.password, port: port, plugins: "readWriteSplitting,failover", + connectionProvider: provider, failoverTimeoutMs: 400000, enableTelemetry: true, telemetryTracesBackend: "OTLP", @@ -97,8 +99,7 @@ describe("pooled connection autoscaling", () => { afterEach(async () => { if (provider !== null) { try { - await ConnectionProviderManager.releaseResources(); - ConnectionProviderManager.resetProvider(); + await provider.releaseResources(); } catch (error) { // pass } @@ -116,7 +117,6 @@ describe("pooled connection autoscaling", () => { // Set provider. provider = new InternalPooledConnectionProvider(new AwsPoolConfig({ maxConnections: numInstances })); - ConnectionProviderManager.setConnectionProvider(provider); // Initialize clients. try { @@ -124,7 +124,7 @@ describe("pooled connection autoscaling", () => { const host = instances[i].host; const port = instances[i].port; if (host && port) { - const config: any = await initDefaultConfig(host, port); + const config: any = await initDefaultConfig(host, port, provider); const client = initClientFunc(config); client.on("error", (error: any): void => { logger.debug(`event emitter threw error: ${error.message}`); @@ -145,7 +145,7 @@ describe("pooled connection autoscaling", () => { // Connect to instance. try { - const config = await initDefaultConfig(env.databaseInfo.writerInstanceEndpoint, env.databaseInfo.instanceEndpointPort); + const config = await initDefaultConfig(env.databaseInfo.writerInstanceEndpoint, env.databaseInfo.instanceEndpointPort, provider); newInstanceClient = initClientFunc(config); await newInstanceClient.connect(); connectionsSet.add(newInstanceClient); @@ -197,7 +197,6 @@ describe("pooled connection autoscaling", () => { // Set provider. provider = new InternalPooledConnectionProvider(new AwsPoolConfig({ maxConnections: numInstances })); - ConnectionProviderManager.setConnectionProvider(provider); // Initialize clients. try { @@ -205,7 +204,7 @@ describe("pooled connection autoscaling", () => { const host = instances[i].host; const port = instances[i].port; if (host && port) { - const config: any = await initConfigWithFailover(host, port); + const config: any = await initConfigWithFailover(host, port, provider); const client = initClientFunc(config); client.on("error", (error: any): void => { logger.debug(`event emitter threw error: ${error.message}`); @@ -226,7 +225,7 @@ describe("pooled connection autoscaling", () => { // Connect to instance. try { - const config = await initConfigWithFailover(newInstance.host, newInstance.port); + const config = await initConfigWithFailover(newInstance.host, newInstance.port, provider); newInstanceClient = initClientFunc(config); await newInstanceClient.connect(); connectionsSet.add(newInstanceClient); diff --git a/tests/integration/container/tests/read_write_splitting.test.ts b/tests/integration/container/tests/read_write_splitting.test.ts index e34d1b6e..bf470ca1 100644 --- a/tests/integration/container/tests/read_write_splitting.test.ts +++ b/tests/integration/container/tests/read_write_splitting.test.ts @@ -111,8 +111,7 @@ describe("aurora read write splitting", () => { } if (provider !== null) { try { - await ConnectionProviderManager.releaseResources(); - ConnectionProviderManager.resetProvider(); + await provider.releaseResources(); } catch (error) { // pass } @@ -455,10 +454,9 @@ describe("aurora read write splitting", () => { async () => { const config = await initConfigWithFailover(env.databaseInfo.writerInstanceEndpoint, env.databaseInfo.instanceEndpointPort, false); provider = new InternalPooledConnectionProvider(); - ConnectionProviderManager.setConnectionProvider(provider); + config["connectionProvider"] = provider; client = initClientFunc(config); - await client.connect(); const initialWriterId = await auroraTestUtility.queryInstanceId(client); provider.logConnections(); @@ -491,8 +489,6 @@ describe("aurora read write splitting", () => { "test set read only reuse cached connection", async () => { const config = await initDefaultConfig(env.databaseInfo.writerInstanceEndpoint, env.databaseInfo.instanceEndpointPort, false); - client = initClientFunc(config); - secondaryClient = initClientFunc(config); provider = new InternalPooledConnectionProvider( new AwsPoolConfig({ @@ -501,8 +497,11 @@ describe("aurora read write splitting", () => { maxIdleConnections: 10 }) ); + config["connectionProvider"] = provider; + + client = initClientFunc(config); + secondaryClient = initClientFunc(config); - ConnectionProviderManager.setConnectionProvider(provider); await client.connect(); await client.end(); @@ -511,8 +510,7 @@ describe("aurora read write splitting", () => { provider.logConnections(); try { await secondaryClient.end(); - await ConnectionProviderManager.releaseResources(); - ConnectionProviderManager.resetProvider(); + await provider.releaseResources(); } catch (error) { // pass } @@ -526,15 +524,14 @@ describe("aurora read write splitting", () => { const config = await initConfigWithFailover(env.proxyDatabaseInfo.writerInstanceEndpoint, env.proxyDatabaseInfo.instanceEndpointPort, true); config["failoverTimeoutMs"] = 1000; - client = initClientFunc(config); - provider = new InternalPooledConnectionProvider({ minConnections: 0, maxConnections: 10, maxIdleConnections: 10 }); - ConnectionProviderManager.setConnectionProvider(provider); + config["connectionProvider"] = provider; + client = initClientFunc(config); await client.connect(); const initialWriterId = await auroraTestUtility.queryInstanceId(client); @@ -558,11 +555,11 @@ describe("aurora read write splitting", () => { "test pooled connection failover in transaction", async () => { const config = await initConfigWithFailover(env.databaseInfo.writerInstanceEndpoint, env.databaseInfo.instanceEndpointPort, false); - client = initClientFunc(config); provider = new InternalPooledConnectionProvider(); - ConnectionProviderManager.setConnectionProvider(provider); + config["connectionProvider"] = provider; + client = initClientFunc(config); await client.connect(); const initialWriterId = await auroraTestUtility.queryInstanceId(client); @@ -596,9 +593,9 @@ describe("aurora read write splitting", () => { const connectionsSet: Set = new Set(); try { provider = new InternalPooledConnectionProvider({ maxConnections: numInstances }); - ConnectionProviderManager.setConnectionProvider(provider); const config = await initDefaultConfig(env.databaseInfo.writerInstanceEndpoint, env.databaseInfo.instanceEndpointPort, false); config["readerHostSelectorStrategy"] = "leastConnections"; + config["connectionProvider"] = provider; // Assume one writer and [size - 1] readers for (let i = 0; i < numInstances - 1; i++) { @@ -639,7 +636,7 @@ describe("aurora read write splitting", () => { const numInstances = env.databaseInfo.instances.length; const numTestConnections = (numInstances - 2) * numOverloadedReaderConnections; provider = new InternalPooledConnectionProvider({ maxConnections: numTestConnections }, myKeyFunc); - ConnectionProviderManager.setConnectionProvider(provider); + config["connectionProvider"] = provider; let overloadedReaderId; const connectionsSet: Set = new Set(); diff --git a/tests/integration/container/tests/read_write_splitting_performance.test.ts b/tests/integration/container/tests/read_write_splitting_performance.test.ts index a2e13444..2915055c 100644 --- a/tests/integration/container/tests/read_write_splitting_performance.test.ts +++ b/tests/integration/container/tests/read_write_splitting_performance.test.ts @@ -78,8 +78,9 @@ describe("rwperformance", () => { setReadOnlyPerfDataList = []; // Internal connection pool results. - ConnectionProviderManager.setConnectionProvider(new InternalPooledConnectionProvider()); const rwPluginWithPoolConfig = initReadWritePluginConfig(env.databaseInfo.writerInstanceEndpoint, env.databaseInfo.clusterEndpointPort); + let provider = new InternalPooledConnectionProvider(); + rwPluginWithPoolConfig["connectionProvider"] = provider; const rwPluginWithPoolData = await measurePerformance(rwPluginWithPoolConfig); readerData = calculateReaderOverhead("Switch to reader", rwPluginWithPoolData, noPluginData); @@ -92,18 +93,17 @@ describe("rwperformance", () => { "ICP" ); - await ConnectionProviderManager.releaseResources(); - ConnectionProviderManager.resetProvider(); + await provider.releaseResources(); setReadOnlyPerfDataList = []; - // Internal connection pool results with warm up. - ConnectionProviderManager.setConnectionProvider(new InternalPooledConnectionProvider()); - // Create an internal connection pool for each instance. + provider = new InternalPooledConnectionProvider(); for (const instance of env.databaseInfo.instances) { if (instance.host && instance.port) { - const client = DriverHelper.getClient(driver)(initReadWritePluginConfig(instance.host, instance.port)); + const instanceConfig = initReadWritePluginConfig(instance.host, instance.port); + instanceConfig["connectionProvider"] = provider; + const client = DriverHelper.getClient(driver)(instanceConfig); await PerfTestUtility.connectWithRetry(client); await client.setReadOnly(true); await client.setReadOnly(false); @@ -123,8 +123,7 @@ describe("rwperformance", () => { "ICPWithWarmUp" ); - await ConnectionProviderManager.releaseResources(); - ConnectionProviderManager.resetProvider(); + await provider.releaseResources(); }, 13200000 ); diff --git a/tests/unit/internal_pool_connection_provider.test.ts b/tests/unit/internal_pool_connection_provider.test.ts index 2ce8e695..ce486ef9 100644 --- a/tests/unit/internal_pool_connection_provider.test.ts +++ b/tests/unit/internal_pool_connection_provider.test.ts @@ -120,7 +120,6 @@ describe("internal pool connection provider test", () => { reset(mockHostListProvider); InternalPooledConnectionProvider.clearDatabasePools(); - ConnectionProviderManager.resetProvider(); }); it("test connect with default mapping", async () => { diff --git a/tests/unit/read_write_splitting.test.ts b/tests/unit/read_write_splitting.test.ts index 42a01ba0..2e86031d 100644 --- a/tests/unit/read_write_splitting.test.ts +++ b/tests/unit/read_write_splitting.test.ts @@ -418,7 +418,7 @@ describe("reader write splitting test", () => { }); const provider: InternalPooledConnectionProvider = new InternalPooledConnectionProvider(config); - ConnectionProviderManager.setConnectionProvider(provider); + properties["connectionProvider"] = provider; const target: ReadWriteSplittingPlugin = spy( new ReadWriteSplittingPlugin(mockPluginServiceInstance, properties, mockHostListProviderService, mockWriterWrapper, clientWrapper_undefined) @@ -459,7 +459,7 @@ describe("reader write splitting test", () => { }; const provider: InternalPooledConnectionProvider = new InternalPooledConnectionProvider(config, myKeyFunc); - ConnectionProviderManager.setConnectionProvider(provider); + properties["connectionProvider"] = provider; const target: ReadWriteSplittingPlugin = spy( new ReadWriteSplittingPlugin(