Skip to content
1 change: 1 addition & 0 deletions dist/config/rds.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ declare const _default: {
connectionLimit: number;
waitForConnections: boolean;
queueLimit: number;
usePool: boolean;
};
};
};
Expand Down
4 changes: 4 additions & 0 deletions dist/config/rds.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ export default {
queueLimit: Number(
process.env.LESGO_AWS_RDS_AURORA_MYSQL_PROXY_QUEUE_LIMIT || '0'
),
usePool:
process.env.LESGO_AWS_RDS_AURORA_MYSQL_USE_POOL === 'false'
? false
: true,
},
},
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
declare const disconnectMySQLClient: () => Promise<void>;
export default disconnectMySQLClient;
59 changes: 59 additions & 0 deletions dist/services/RDSAuroraMySQLProxyService/disconnectMySQLClient.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
var __awaiter =
(this && this.__awaiter) ||
function (thisArg, _arguments, P, generator) {
function adopt(value) {
return value instanceof P
? value
: new P(function (resolve) {
resolve(value);
});
}
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
}
function rejected(value) {
try {
step(generator['throw'](value));
} catch (e) {
reject(e);
}
}
function step(result) {
result.done
? resolve(result.value)
: adopt(result.value).then(fulfilled, rejected);
}
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { logger } from '../../utils';
import { singleton } from './getMySQLProxyClient';
const FILE = 'lesgo.services.RDSAuroraMySQLProxyService.disconnectMySQLClient';
const disconnectMySQLClient = () =>
__awaiter(void 0, void 0, void 0, function* () {
const singletonConns = Object.keys(singleton);
if (singletonConns.length === 0) {
logger.debug(`${FILE}::NO_CONNECTIONS_TO_DISCONNECT`);
return;
}
logger.debug(`${FILE}::PREPARING_TO_DISCONNECT`, {
singletonConns,
});
singletonConns.forEach(singletonConn =>
__awaiter(void 0, void 0, void 0, function* () {
try {
yield singleton[singletonConn].end();
delete singleton[singletonConn];
logger.debug(`${FILE}::COMPLETED`, { singletonConn });
} catch (err) {
logger.error(`${FILE}::ERROR`, { singletonConn, err });
}
})
);
});
export default disconnectMySQLClient;
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Pool, ConnectionOptions } from 'mysql2/promise';
import { Pool, Connection, ConnectionOptions } from 'mysql2/promise';
import { RDSAuroraMySQLProxyClientOptions } from '../../types/aws';
export interface Singleton {
[key: string]: Pool;
[key: string]: Pool | Connection;
}
export declare const singleton: Singleton;
declare const getMySQLProxyClient: (connOptions?: ConnectionOptions, clientOpts?: RDSAuroraMySQLProxyClientOptions) => Promise<Pool>;
declare const getMySQLProxyClient: (connOptions?: ConnectionOptions, clientOpts?: RDSAuroraMySQLProxyClientOptions) => Promise<Pool | Connection>;
export default getMySQLProxyClient;
50 changes: 34 additions & 16 deletions dist/services/RDSAuroraMySQLProxyService/getMySQLProxyClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,21 @@ var __awaiter =
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { createPool } from 'mysql2/promise';
import { createPool, createConnection } from 'mysql2/promise';
import { logger, isEmpty, validateFields } from '../../utils';
import { rds as rdsConfig } from '../../config';
import { getSecretValue } from '../../utils/secretsmanager';
const FILE = 'lesgo.services.RDSAuroraMySQLProxyService.getMySQLProxyClient';
export const singleton = {};
const getMySQLProxyClient = (connOptions, clientOpts) =>
__awaiter(void 0, void 0, void 0, function* () {
var _a;
const options = validateFields(clientOpts || {}, [
{ key: 'region', type: 'string', required: false },
{ key: 'singletonConn', type: 'string', required: false },
{ key: 'dbCredentialsSecretId', type: 'string', required: false },
{ key: 'databaseName', type: 'string', required: false },
{ key: 'usePool', type: 'boolean', required: false },
]);
const region = options.region || rdsConfig.aurora.mysql.region;
const singletonConn = options.singletonConn || 'default';
Expand All @@ -52,6 +54,10 @@ const getMySQLProxyClient = (connOptions, clientOpts) =>
rdsConfig.aurora.mysql.proxy.dbCredentialsSecretId;
const databaseName =
options.databaseName || rdsConfig.aurora.mysql.databaseName;
const usePool =
(_a = options.usePool) !== null && _a !== void 0
? _a
: rdsConfig.aurora.mysql.proxy.usePool;
if (!isEmpty(singleton[singletonConn])) {
logger.debug(`${FILE}::REUSE_RDS_CONNECTION`);
return singleton[singletonConn];
Expand All @@ -64,25 +70,37 @@ const getMySQLProxyClient = (connOptions, clientOpts) =>
singletonConn,
}
);
const poolOptions = {
connectionLimit: rdsConfig.aurora.mysql.proxy.connectionLimit || 10,
waitForConnections:
rdsConfig.aurora.mysql.proxy.waitForConnections || true,
queueLimit: rdsConfig.aurora.mysql.proxy.queueLimit || 0,
};
const connOpts = Object.assign(
{
host: rdsConfig.aurora.mysql.proxy.host || dbCredentials.host,
database: databaseName,
port: rdsConfig.aurora.mysql.proxy.port || dbCredentials.port || 3306,
connectionLimit: rdsConfig.aurora.mysql.proxy.connectionLimit || 10,
waitForConnections:
rdsConfig.aurora.mysql.proxy.waitForConnections || true,
queueLimit: rdsConfig.aurora.mysql.proxy.queueLimit || 0,
},
Object.assign(
{
host: rdsConfig.aurora.mysql.proxy.host || dbCredentials.host,
database: databaseName,
port: rdsConfig.aurora.mysql.proxy.port || dbCredentials.port || 3306,
},
usePool ? poolOptions : {}
),
connOptions
);
logger.debug(`${FILE}::CONN_OPTS`, { connOpts });
const dbPool = createPool(
Object.assign(
{ user: dbCredentials.username, password: dbCredentials.password },
connOpts
)
);
const dbPool = usePool
? createPool(
Object.assign(
{ user: dbCredentials.username, password: dbCredentials.password },
connOpts
)
)
: yield createConnection(
Object.assign(
{ user: dbCredentials.username, password: dbCredentials.password },
connOpts
)
);
singleton[singletonConn] = dbPool;
logger.debug(`${FILE}::NEW_RDS_CONNECTION`);
return dbPool;
Expand Down
1 change: 1 addition & 0 deletions dist/services/RDSAuroraMySQLProxyService/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { default as disconnectMySQLProxyClient } from './disconnectMySQLProxyClient';
export { default as disconnectMySQLClient } from './disconnectMySQLClient';
export { default as getMySQLProxyClient } from './getMySQLProxyClient';
export { default as query } from './query';
1 change: 1 addition & 0 deletions dist/services/RDSAuroraMySQLProxyService/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { default as disconnectMySQLProxyClient } from './disconnectMySQLProxyClient';
export { default as disconnectMySQLClient } from './disconnectMySQLClient';
export { default as getMySQLProxyClient } from './getMySQLProxyClient';
export { default as query } from './query';
1 change: 1 addition & 0 deletions dist/types/aws.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export interface ClientOptions {
export interface RDSAuroraMySQLProxyClientOptions extends ClientOptions {
dbCredentialsSecretId?: string;
databaseName?: string;
usePool?: boolean;
}
5 changes: 5 additions & 0 deletions dist/utils/db/mysql/proxy/disconnectMySQLDb.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/**
* @deprecated Disconnect db is no longer to be used due to the use of ConnectionPool
*/
declare const disconnectMySQLDb: () => Promise<void>;
export default disconnectMySQLDb;
8 changes: 8 additions & 0 deletions dist/utils/db/mysql/proxy/disconnectMySQLDb.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { disconnectMySQLClient } from '../../../../services/RDSAuroraMySQLProxyService';
/**
* @deprecated Disconnect db is no longer to be used due to the use of ConnectionPool
*/
const disconnectMySQLDb = () => {
return disconnectMySQLClient();
};
export default disconnectMySQLDb;
2 changes: 1 addition & 1 deletion dist/utils/db/mysql/proxy/getClient.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ConnectionOptions } from 'mysql2/promise';
import { RDSAuroraMySQLProxyClientOptions } from '../../../../types/aws';
declare const getClient: (connOptions?: ConnectionOptions, clientOpts?: RDSAuroraMySQLProxyClientOptions) => Promise<import("mysql2/promise").Pool>;
declare const getClient: (connOptions?: ConnectionOptions, clientOpts?: RDSAuroraMySQLProxyClientOptions) => Promise<import("mysql2/promise").Pool | import("mysql2/promise").Connection>;
export default getClient;
1 change: 1 addition & 0 deletions dist/utils/db/mysql/proxy/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { default as disconnectDb } from './disconnectDb';
export { default as disconnectMySQLDb } from './disconnectMySQLDb';
export { default as getClient } from './getClient';
export { default as query } from './query';
1 change: 1 addition & 0 deletions dist/utils/db/mysql/proxy/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { default as disconnectDb } from './disconnectDb';
export { default as disconnectMySQLDb } from './disconnectMySQLDb';
export { default as getClient } from './getClient';
export { default as query } from './query';
4 changes: 4 additions & 0 deletions src/config/rds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ export default {
queueLimit: Number(
process.env.LESGO_AWS_RDS_AURORA_MYSQL_PROXY_QUEUE_LIMIT || '0'
),
usePool:
process.env.LESGO_AWS_RDS_AURORA_MYSQL_USE_POOL === 'false'
? false
: true,
},
},
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { ConnectionOptions } from 'mysql2/promise';
import getMySQLProxyClient, { singleton } from '../getMySQLProxyClient';
import { disconnectMySQLClient } from '../../RDSAuroraMySQLProxyService';
import { query } from '../../RDSAuroraMySQLProxyService';
import { getSecretValue } from '../../../utils/secretsmanager';

jest.mock('../../../utils/secretsmanager');

describe('query', () => {
afterEach(() => {
jest.clearAllMocks();
});

it('clear all singleton', async () => {
const connOptions: ConnectionOptions = {
host: 'localhost',
user: 'root',
password: 'password',
database: 'test',
};
const clientOpts = {
region: 'us-west-2',
endpoint: 'http://localhost:8000',
};
(getSecretValue as jest.Mock).mockResolvedValue(connOptions);

await Promise.all([
getMySQLProxyClient(connOptions, clientOpts),
getMySQLProxyClient(connOptions, {
...clientOpts,
singletonConn: 'test1',
}),
]);

expect(Object.keys(singleton).length).toBe(2);

const spy = jest.spyOn(Object.values(singleton)[0], 'end');

await disconnectMySQLClient();

expect(Object.keys(singleton).length).toBe(0);
expect(spy).toHaveBeenCalled();
});
});
26 changes: 26 additions & 0 deletions src/services/RDSAuroraMySQLProxyService/disconnectMySQLClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { logger } from '../../utils';
import { singleton } from './getMySQLProxyClient';

const FILE = 'lesgo.services.RDSAuroraMySQLProxyService.disconnectMySQLClient';

const disconnectMySQLClient = async () => {
const singletonConns = Object.keys(singleton);
if (singletonConns.length === 0) {
logger.debug(`${FILE}::NO_CONNECTIONS_TO_DISCONNECT`);
return;
}
logger.debug(`${FILE}::PREPARING_TO_DISCONNECT`, {
singletonConns,
});
singletonConns.forEach(async singletonConn => {
try {
await singleton[singletonConn].end();
delete singleton[singletonConn];
logger.debug(`${FILE}::COMPLETED`, { singletonConn });
} catch (err) {
logger.error(`${FILE}::ERROR`, { singletonConn, err });
}
});
};

export default disconnectMySQLClient;
38 changes: 28 additions & 10 deletions src/services/RDSAuroraMySQLProxyService/getMySQLProxyClient.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { Pool, ConnectionOptions, createPool } from 'mysql2/promise';
import {
Pool,
Connection,
ConnectionOptions,
createPool,
createConnection,
} from 'mysql2/promise';
import { logger, isEmpty, validateFields } from '../../utils';
import { rds as rdsConfig } from '../../config';
import { getSecretValue } from '../../utils/secretsmanager';
Expand All @@ -7,7 +13,7 @@ import { RDSAuroraMySQLProxyClientOptions } from '../../types/aws';
const FILE = 'lesgo.services.RDSAuroraMySQLProxyService.getMySQLProxyClient';

export interface Singleton {
[key: string]: Pool;
[key: string]: Pool | Connection;
}

export const singleton: Singleton = {};
Expand All @@ -21,6 +27,7 @@ const getMySQLProxyClient = async (
{ key: 'singletonConn', type: 'string', required: false },
{ key: 'dbCredentialsSecretId', type: 'string', required: false },
{ key: 'databaseName', type: 'string', required: false },
{ key: 'usePool', type: 'boolean', required: false },
]);

const region = options.region || rdsConfig.aurora.mysql.region;
Expand All @@ -29,6 +36,7 @@ const getMySQLProxyClient = async (
rdsConfig.aurora.mysql.proxy.dbCredentialsSecretId) as string;
const databaseName =
options.databaseName || rdsConfig.aurora.mysql.databaseName;
const usePool = options.usePool ?? rdsConfig.aurora.mysql.proxy.usePool;

if (!isEmpty(singleton[singletonConn])) {
logger.debug(`${FILE}::REUSE_RDS_CONNECTION`);
Expand All @@ -40,22 +48,32 @@ const getMySQLProxyClient = async (
singletonConn,
});

const poolOptions = {
connectionLimit: rdsConfig.aurora.mysql.proxy.connectionLimit || 10,
waitForConnections: rdsConfig.aurora.mysql.proxy.waitForConnections || true,
queueLimit: rdsConfig.aurora.mysql.proxy.queueLimit || 0,
};

const connOpts = {
host: rdsConfig.aurora.mysql.proxy.host || dbCredentials.host,
database: databaseName,
port: rdsConfig.aurora.mysql.proxy.port || dbCredentials.port || 3306,
connectionLimit: rdsConfig.aurora.mysql.proxy.connectionLimit || 10,
waitForConnections: rdsConfig.aurora.mysql.proxy.waitForConnections || true,
queueLimit: rdsConfig.aurora.mysql.proxy.queueLimit || 0,
...(usePool ? poolOptions : {}),
...connOptions,
};
logger.debug(`${FILE}::CONN_OPTS`, { connOpts });

const dbPool = createPool({
user: dbCredentials.username,
password: dbCredentials.password,
...connOpts,
});
const dbPool = usePool
? createPool({
user: dbCredentials.username,
password: dbCredentials.password,
...connOpts,
})
: await createConnection({
user: dbCredentials.username,
password: dbCredentials.password,
...connOpts,
});

singleton[singletonConn] = dbPool;
logger.debug(`${FILE}::NEW_RDS_CONNECTION`);
Expand Down
1 change: 1 addition & 0 deletions src/services/RDSAuroraMySQLProxyService/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { default as disconnectMySQLProxyClient } from './disconnectMySQLProxyClient';
export { default as disconnectMySQLClient } from './disconnectMySQLClient';
export { default as getMySQLProxyClient } from './getMySQLProxyClient';
export { default as query } from './query';
1 change: 1 addition & 0 deletions src/types/aws.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ export interface ClientOptions {
export interface RDSAuroraMySQLProxyClientOptions extends ClientOptions {
dbCredentialsSecretId?: string;
databaseName?: string;
usePool?: boolean;
}
Loading