Created
July 25, 2025 10:19
-
-
Save leegilmorecode/db98bf58e8f0019d4c9398bf8837d04f to your computer and use it in GitHub Desktop.
An example of DSQL connection management without caching
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { DsqlSigner } from '@aws-sdk/dsql-signer'; | |
import { config } from '@config'; | |
import { initModels } from '@models'; | |
import { logger } from '@shared'; | |
import pg from 'pg'; | |
import { Sequelize } from 'sequelize'; | |
const clusterId = config.get('clusterId'); | |
const region = config.get('region'); | |
const databaseUser = config.get('databaseUser'); | |
const databasePort = config.get('databasePort'); | |
const databaseLogging = config.get('databaseLogging'); | |
let cachedToken: { token: string; expiresAt: number } | null = null; | |
function generateDsqlEndpoint(clusterId: string, region: string): string { | |
if (!clusterId || typeof clusterId !== 'string') { | |
throw new Error('ClusterId must be a non-empty string'); | |
} | |
if (!region || typeof region !== 'string') { | |
throw new Error('Region must be a non-empty string'); | |
} | |
return `${clusterId}.dsql.${region}.on.aws`; | |
} | |
async function getPasswordToken( | |
host: string, | |
user: string, | |
region: string, | |
): Promise<string> { | |
const now = Date.now(); | |
if (cachedToken && cachedToken.expiresAt > now) { | |
logger.debug(`Using cached token for user ${user}`); | |
return cachedToken.token; | |
} | |
logger.debug(`Generating new token for user ${user}`); | |
const signer = new DsqlSigner({ hostname: host, region }); | |
let token: string; | |
if (user === 'admin') { | |
token = await signer.getDbConnectAdminAuthToken(); | |
} else { | |
(signer as any).user = user; | |
token = await signer.getDbConnectAuthToken(); | |
} | |
cachedToken = { | |
token, | |
expiresAt: now + 15 * 60 * 1000, // 15 minutes | |
}; | |
return token; | |
} | |
export async function createSequelizeInstance(): Promise<Sequelize> { | |
const host = generateDsqlEndpoint(clusterId, region); | |
const sequelize = new Sequelize('postgres', databaseUser, '', { | |
host, | |
port: databasePort, | |
dialect: 'postgres', | |
dialectModule: pg, | |
logging: databaseLogging ? console.log : false, | |
define: { timestamps: false }, | |
dialectOptions: { | |
user: databaseUser, | |
clientMinMessages: 'ignore', | |
skipIndexes: true, | |
ssl: { | |
rejectUnauthorized: true, | |
}, | |
}, | |
pool: { | |
max: 2, | |
min: 0, | |
idle: 0, | |
acquire: 3000, | |
evict: 900000, // 15 minutes | |
}, | |
hooks: { | |
beforeConnect: async (config) => { | |
const token = await getPasswordToken(host, databaseUser, region); | |
config.password = token; | |
}, | |
afterConnect: async (connection) => { | |
logger.info('Successfully opened DSQL connection'); | |
await (connection as any).query('SET search_path TO public'); | |
}, | |
}, | |
}); | |
logger.info('Initializing Sequelize models'); | |
await initModels(sequelize); | |
await sequelize.authenticate(); | |
return sequelize; | |
} | |
export async function closeSequelizeConnection( | |
sequelize: Sequelize, | |
): Promise<void> { | |
try { | |
logger.info('Closing Sequelize connection pool'); | |
await sequelize.connectionManager.close(); | |
} catch (err) { | |
logger.error(`Error closing Sequelize connection: ${err}`); | |
} | |
cachedToken = null; | |
logger.debug('Token cache reset'); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment