-
Notifications
You must be signed in to change notification settings - Fork 57
Expand file tree
/
Copy pathgetConnection.ts
More file actions
102 lines (92 loc) · 2.47 KB
/
Copy pathgetConnection.ts
File metadata and controls
102 lines (92 loc) · 2.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import { CamelCasePlugin, Kysely, PostgresDialect } from 'kysely';
import { Database } from './database-schema';
import { Pool, PoolConfig } from 'pg';
import { Signer } from '@aws-sdk/rds-signer';
import { environment } from './environment';
import fs from 'fs';
let dbInstance: Promise<Kysely<Database>> | null = null;
let tokenExpirationTime: number = 0;
let pool: Pool | null = null;
let poolConfig: PoolConfig;
export async function getConnection<T>({
cb,
}: {
cb: (r: Kysely<Database>) => T;
}): Promise<T> {
if (!dbInstance) {
dbInstance = establishConnection();
}
if (Date.now() > tokenExpirationTime) {
if (pool) {
await resetPoolPassword();
}
}
const awaitedInstance = await dbInstance;
return await cb(awaitedInstance);
}
async function establishConnection(): Promise<Kysely<Database>> {
try {
poolConfig = getPoolConfig();
let token: string | null = null;
token = await getToken();
pool = new Pool({ ...poolConfig, password: token });
return new Kysely<Database>({
dialect: new PostgresDialect({
pool,
}),
plugins: [new CamelCasePlugin()],
});
} catch (e) {
dbInstance = null;
throw new Error(`Failed to connect to database: ${e}`);
}
}
async function generateRDSAuthToken() {
const signer = new Signer({
hostname: environment.rds.pool.host,
port: 5432,
region: environment.region,
username: environment.rds.pool.user,
});
const token = await signer.getAuthToken();
return token;
}
async function getToken() {
const token =
environment.nodeEnv !== 'production'
? environment.rds.pool.password
: await generateRDSAuthToken();
tokenExpirationTime = Date.now() + 13 * 60 * 1000; // rds auth token expires every 15min. So refresh every 13min
return token;
}
let tokenPromise: Promise<string> | null;
async function resetPoolPassword() {
if (pool) {
if (!tokenPromise) {
tokenPromise = getToken();
}
let token;
try {
token = await tokenPromise;
pool.options.password = token;
} catch (e) {
tokenExpirationTime = 0;
throw new Error(`Could not reset db password: ${e}`);
} finally {
tokenPromise = null;
}
}
}
function getPoolConfig(): PoolConfig {
if (!poolConfig) {
poolConfig = {
...environment.rds.pool,
ssl: environment.rds.useGlobalCert
? {
ca: fs.readFileSync('global-bundle.pem').toString(),
}
: undefined,
};
}
return poolConfig;
}