Skip to content

Commit

Permalink
feat: wrapper connect and query timeouts (#342)
Browse files Browse the repository at this point in the history
  • Loading branch information
crystall-bitquill authored Dec 12, 2024
1 parent e58e8e9 commit f91e999
Show file tree
Hide file tree
Showing 10 changed files with 95 additions and 22 deletions.
4 changes: 4 additions & 0 deletions common/lib/driver_dialect/driver_dialect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,9 @@ export interface DriverDialect {

getAwsPoolClient(props: any): AwsPoolClient;

setConnectTimeout(props: Map<string, any>, wrapperConnectTimeout?: any): void;

setQueryTimeout(props: Map<string, any>, sql?: any, wrapperConnectTimeout?: any): void;

setKeepAliveProperties(props: Map<string, any>, keepAliveProps: any): void;
}
7 changes: 6 additions & 1 deletion common/lib/mysql_client_wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ import { ClientWrapper } from "./client_wrapper";
import { HostInfo } from "./host_info";
import { ClientUtils } from "./utils/client_utils";
import { uniqueId } from "../logutils";
import { DriverDialect } from "./driver_dialect/driver_dialect";

/*
This is an internal wrapper class for the target community driver client created by the MySQL2DriverDialect.
*/
export class MySQLClientWrapper implements ClientWrapper {
private readonly driverDialect: DriverDialect;
readonly client: any;
readonly hostInfo: HostInfo;
readonly properties: Map<string, string>;
Expand All @@ -34,15 +36,18 @@ export class MySQLClientWrapper implements ClientWrapper {
* @param targetClient The community driver client created for an instance.
* @param hostInfo Host information for the connected instance.
* @param properties Connection properties for the target client.
* @param driverDialect The driver dialect to obtain driver-specific information.
*/
constructor(targetClient: any, hostInfo: HostInfo, properties: Map<string, any>) {
constructor(targetClient: any, hostInfo: HostInfo, properties: Map<string, any>, driverDialect: DriverDialect) {
this.client = targetClient;
this.hostInfo = hostInfo;
this.properties = properties;
this.driverDialect = driverDialect;
this.id = uniqueId("MySQLClient_");
}

query(sql: any): Promise<any> {
this.driverDialect.setQueryTimeout(this.properties, sql);
return this.client?.query(sql);
}

Expand Down
21 changes: 16 additions & 5 deletions common/lib/utils/client_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,26 @@ import { getTimeoutTask } from "./utils";
import { Messages } from "./messages";
import { AwsWrapperError, InternalQueryTimeoutError } from "./errors";
import { WrapperProperties } from "../wrapper_property";
import { logger } from "../../logutils";

export class ClientUtils {
static hasWarnedDeprecation: boolean = false;
static async queryWithTimeout(newPromise: Promise<any>, props: Map<string, any>, timeValue?: number): Promise<any> {
const timer: any = {};
const timeoutTask = getTimeoutTask(
timer,
Messages.get("ClientUtils.queryTaskTimeout"),
timeValue ?? WrapperProperties.INTERNAL_QUERY_TIMEOUT.get(props)
);
let timeout = timeValue;
if (props.has(WrapperProperties.INTERNAL_QUERY_TIMEOUT.name)) {
timeout = WrapperProperties.INTERNAL_QUERY_TIMEOUT.get(props);
if (!ClientUtils.hasWarnedDeprecation) {
logger.warn(
"The connection configuration property 'mysqlQueryTimeout' is deprecated since version 1.1.0. Please use 'wrapperQueryTimeout' instead."
);
ClientUtils.hasWarnedDeprecation = true;
}
}
if (!timeout) {
timeout = WrapperProperties.WRAPPER_QUERY_TIMEOUT.get(props);
}
const timeoutTask = getTimeoutTask(timer, Messages.get("ClientUtils.queryTaskTimeout"), timeout);
return await Promise.race([timeoutTask, newPromise])
.catch((error: any) => {
if (error instanceof InternalQueryTimeoutError) {
Expand Down
1 change: 1 addition & 0 deletions common/lib/utils/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"ConnectionProvider.unsupportedHostSelectorStrategy": "Unsupported host selection strategy '%s' specified for this connection provider '%s'. Please visit the documentation for all supported strategies.",
"ConnectionPluginChainBuilder.errorImportingPlugin": "The plugin could not be imported due to error '%s'. Please ensure the required dependencies have been installed. Plugin: '%s'",
"ClientUtils.queryTaskTimeout": "Client query task timed out, if a network error did not occur, please review the usage of the 'mysqlQueryTimeout' connection parameter.",
"ClientUtils.connectTimeout": "Client connect timed out.",
"DialectManager.unknownDialectCode": "Unknown dialect code: '%s'.",
"DialectManager.getDialectError": "Was not able to get a database dialect.",
"DefaultPlugin.executingMethod": "Executing method: %s",
Expand Down
15 changes: 15 additions & 0 deletions common/lib/wrapper_property.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,27 @@ export class WrapperProperties {
null
);

/**
* @deprecated since version 1.1.0 and replaced by wrapper property WRAPPER_QUERY_TIMEOUT.
*/
static readonly INTERNAL_QUERY_TIMEOUT = new WrapperProperty<number>(
"mysqlQueryTimeout",
"Timeout in milliseconds for the wrapper to execute queries against MySQL database engines",
20000
);

static readonly WRAPPER_CONNECT_TIMEOUT = new WrapperProperty<number>(
"wrapperConnectTimeout",
"Timeout in milliseconds for the wrapper to create a connection.",
10000
);

static readonly WRAPPER_QUERY_TIMEOUT = new WrapperProperty<number>(
"wrapperQueryTimeout",
"Timeout in milliseconds for the wrapper to execute queries.",
20000
);

static readonly TRANSFER_SESSION_STATE_ON_SWITCH = new WrapperProperty<boolean>(
"transferSessionStateOnSwitch",
"Enables session state transfer to a new connection.",
Expand Down
Loading

0 comments on commit f91e999

Please sign in to comment.