diff --git a/common/lib/abstract_connection_plugin.ts b/common/lib/abstract_connection_plugin.ts index 3d38ada8..7a47c804 100644 --- a/common/lib/abstract_connection_plugin.ts +++ b/common/lib/abstract_connection_plugin.ts @@ -24,11 +24,11 @@ export abstract class AbstractConnectionPlugin implements ConnectionPlugin { abstract getSubscribedMethods(): Set; connect(hostInfo: HostInfo, props: Map, isInitialConnection: boolean, connectFunc: () => Promise): Promise { - throw new Error("Method not implemented."); + return connectFunc(); } forceConnect(hostInfo: HostInfo, props: Map, isInitialConnection: boolean, forceConnectFunc: () => Promise): Promise { - throw new Error("Method not implemented."); + return forceConnectFunc(); } execute(methodName: string, methodFunc: () => Promise, methodArgs: any[]): Promise { @@ -41,14 +41,12 @@ export abstract class AbstractConnectionPlugin implements ConnectionPlugin { hostListProviderService: HostListProviderService, initHostProviderFunc: () => void ): void { - throw new Error("Method not implemented."); + initHostProviderFunc(); } notifyConnectionChanged(changes: Set): OldConnectionSuggestionAction { - throw new Error("Method not implemented."); + return OldConnectionSuggestionAction.NO_OPINION; } - notifyNodeListChanged(changes: Map>): void { - throw new Error("Method not implemented."); - } + notifyNodeListChanged(changes: Map>): void {} } diff --git a/common/lib/connection_plugin_chain_builder.ts b/common/lib/connection_plugin_chain_builder.ts index b54f4a12..d9905e21 100644 --- a/common/lib/connection_plugin_chain_builder.ts +++ b/common/lib/connection_plugin_chain_builder.ts @@ -22,6 +22,7 @@ import { WrapperProperties } from "./wrapper_property"; import { AwsWrapperError } from "./utils/aws_wrapper_error"; import { Messages } from "./utils/messages"; import { DefaultPlugin } from "./plugins/default_plugin"; +import { ExecuteTimePluginFactory } from "./plugins/execute_time_plugin"; import { ConnectTimePluginFactory } from "./plugins/connect_time_plugin"; import { AwsSecretsManagerPluginFactory } from "./authentication/aws_secrets_manager_plugin"; @@ -35,6 +36,7 @@ export class ConnectionPluginChainBuilder { static readonly PLUGIN_FACTORIES = new Map([ ["iam", IamAuthenticationPluginFactory], + ["executeTime", ExecuteTimePluginFactory], ["connectTime", ConnectTimePluginFactory], ["secretsManager", AwsSecretsManagerPluginFactory], ["failover", FailoverPluginFactory] diff --git a/common/lib/plugins/default_plugin.ts b/common/lib/plugins/default_plugin.ts index 24d462ac..16cf833c 100644 --- a/common/lib/plugins/default_plugin.ts +++ b/common/lib/plugins/default_plugin.ts @@ -49,9 +49,6 @@ export class DefaultPlugin extends AbstractConnectionPlugin { override execute(methodName: string, methodFunc: () => Type): Type { logger.debug(Messages.get("DefaultPlugin.executingMethod", methodName)); - const start = performance.now(); - const res = methodFunc(); - logger.debug(`Execution time for plugin ${this.id}: ${performance.now() - start} ms`); - return res; + return methodFunc(); } } diff --git a/common/lib/plugins/execute_time_plugin.ts b/common/lib/plugins/execute_time_plugin.ts new file mode 100644 index 00000000..4e2e77b3 --- /dev/null +++ b/common/lib/plugins/execute_time_plugin.ts @@ -0,0 +1,59 @@ +/* + Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"). + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import { logger } from "../../logutils"; +import { AbstractConnectionPlugin } from "../abstract_connection_plugin"; +import { ConnectionPlugin } from "../connection_plugin"; +import { ConnectionPluginFactory } from "../plugin_factory"; +import { PluginService } from "../plugin_service"; +import { Messages } from "../utils/messages"; +import { getTimeInNanos } from "../utils/utils"; + +export class ExecuteTimePlugin extends AbstractConnectionPlugin { + private static readonly subscribedMethods: Set = new Set(["*"]); + private static executeTime: bigint = 0n; + + public override getSubscribedMethods(): Set { + return ExecuteTimePlugin.subscribedMethods; + } + + public override async execute(methodName: string, methodFunc: () => Promise, methodArgs: any[]): Promise { + const startTime = getTimeInNanos(); + + const result = await methodFunc(); + + const elapsedTimeNanos = getTimeInNanos() - startTime; + + // Convert from ns to ms + logger.debug(Messages.get("ExecuteTimePlugin.executeTime", methodName, (elapsedTimeNanos / 1000000n).toString())); + ExecuteTimePlugin.executeTime += elapsedTimeNanos; + return result; + } + + public static resetExecuteTime(): void { + ExecuteTimePlugin.executeTime = 0n; + } + + public static getTotalExecuteTime(): bigint { + return ExecuteTimePlugin.executeTime; + } +} + +export class ExecuteTimePluginFactory implements ConnectionPluginFactory { + getInstance(pluginService: PluginService, properties: Map): ConnectionPlugin { + return new ExecuteTimePlugin(); + } +} diff --git a/common/lib/plugins/failover/failover_plugin.ts b/common/lib/plugins/failover/failover_plugin.ts index ced0cc6e..4dfe3bfa 100644 --- a/common/lib/plugins/failover/failover_plugin.ts +++ b/common/lib/plugins/failover/failover_plugin.ts @@ -29,6 +29,7 @@ import { ClusterAwareReaderFailoverHandler } from "./reader_failover_handler"; import { SubscribedMethodHelper } from "../../utils/subscribed_method_helper"; import { HostChangeOptions } from "../../host_change_options"; import { ClusterAwareWriterFailoverHandler } from "./writer_failover_handler"; +import { Messages } from "../../utils/messages"; export class FailoverPlugin extends AbstractConnectionPlugin { private static readonly subscribedMethods: Set = new Set([ @@ -97,13 +98,10 @@ export class FailoverPlugin extends AbstractConnectionPlugin { override async execute(methodName: string, methodFunc: () => Promise): Promise { try { - const start = performance.now(); if (this.canUpdateTopology(methodName)) { await this.updateTopology(false); } - const res = methodFunc(); - logger.debug(`Execution time for plugin ${this.id}: ${performance.now() - start} ms`); - return res; + return methodFunc(); } catch (e) { logger.debug(e); throw e; diff --git a/common/lib/utils/locales/en.json b/common/lib/utils/locales/en.json index a830a130..5ce12f17 100644 --- a/common/lib/utils/locales/en.json +++ b/common/lib/utils/locales/en.json @@ -38,5 +38,6 @@ "ClusterAwareWriterFailoverHandler.standaloneNode": "[TaskB] Host %s is not yet connected to a cluster. The cluster is still being reconfigured.", "ClusterAwareWriterFailoverHandler.taskBAttemptConnectionToNewWriter": "[TaskB] Trying to connect to a new writer: '%s'", "ClusterAwareWriterFailoverHandler.alreadyWriter": "Current reader connection is actually a new writer connection.", + "ExecuteTimePlugin.executeTime": "Executed method '%s' in %s milliseconds.", "ConnectTimePlugin.connectTime": "Connected to '%s' in %s milliseconds." } diff --git a/tests/unit/execute_time_plugin.test.ts b/tests/unit/execute_time_plugin.test.ts new file mode 100644 index 00000000..a77d7978 --- /dev/null +++ b/tests/unit/execute_time_plugin.test.ts @@ -0,0 +1,44 @@ +/* + Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"). + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import { ExecuteTimePlugin } from "aws-wrapper-common-lib/lib/plugins/execute_time_plugin"; +import { sleep } from "aws-wrapper-common-lib/lib/utils/utils"; + +const mockCallable = jest.fn(); +const timeToSleepMs = 1000; +const timeToSleepNs = timeToSleepMs * 1000000; + +describe("executeTimePluginTest", () => { + it("test_executeTime", async () => { + mockCallable.mockImplementation(async () => { + await sleep(timeToSleepMs); + return null; + }); + + const plugin = new ExecuteTimePlugin(); + + await plugin.execute("query", mockCallable, []); + + expect(ExecuteTimePlugin.getTotalExecuteTime()).toBeGreaterThan(timeToSleepNs); + + await plugin.execute("query", mockCallable, []); + + expect(ExecuteTimePlugin.getTotalExecuteTime()).toBeGreaterThan(timeToSleepNs * 2); + + ExecuteTimePlugin.resetExecuteTime(); + expect(ExecuteTimePlugin.getTotalExecuteTime()).toEqual(0n); + }); +});