Skip to content

Commit 49d9c34

Browse files
feat(database): makes it more robust and failsafe
1 parent b8141f2 commit 49d9c34

File tree

4 files changed

+55
-16
lines changed

4 files changed

+55
-16
lines changed

infra/database.js

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { Pool } from 'pg';
1+
import { Pool, Client } from 'pg';
2+
import retry from 'async-retry';
23
import { ServiceError } from 'errors/index.js';
34

4-
const poolConfiguration = {
5+
const configurations = {
56
user: process.env.POSTGRES_USER,
67
host: process.env.POSTGRES_HOST,
78
database: process.env.POSTGRES_DB,
@@ -15,14 +16,17 @@ const poolConfiguration = {
1516

1617
// https://github.com/filipedeschamps/tabnews.com.br/issues/84
1718
if (['test', 'development'].includes(process.env.NODE_ENV) || process.env.CI) {
18-
delete poolConfiguration.ssl;
19+
delete configurations.ssl;
1920
}
2021

21-
const pool = new Pool(poolConfiguration);
22+
const pool = new Pool(configurations);
2223

2324
async function query(query, params) {
25+
let clientFromPool;
26+
2427
try {
25-
return await pool.query(query, params);
28+
clientFromPool = await tryToGetNewClientFromPool();
29+
return await clientFromPool.query(query, params);
2630
} catch (error) {
2731
const errorObject = new ServiceError({
2832
message: error.message,
@@ -34,15 +38,31 @@ async function query(query, params) {
3438
});
3539
console.error(errorObject);
3640
throw errorObject;
41+
} finally {
42+
if (clientFromPool) {
43+
clientFromPool.release();
44+
}
3745
}
3846
}
3947

40-
async function getNewConnectedClient() {
41-
// When manually creating a new connection like this,
42-
// you need to make sure to close it afterward
43-
// with the .end() method.
44-
try {
48+
async function tryToGetNewClientFromPool() {
49+
const clientFromPool = await retry(newClientFromPool, {
50+
retries: 50,
51+
minTimeout: 0,
52+
factor: 1.3,
53+
});
54+
55+
return clientFromPool;
56+
57+
async function newClientFromPool() {
4558
return await pool.connect();
59+
}
60+
}
61+
62+
async function getNewClient() {
63+
try {
64+
const client = await tryToGetNewClient();
65+
return client;
4666
} catch (error) {
4767
const errorObject = new ServiceError({
4868
message: error.message,
@@ -52,9 +72,25 @@ async function getNewConnectedClient() {
5272
console.error(errorObject);
5373
throw errorObject;
5474
}
75+
76+
async function tryToGetNewClient() {
77+
const client = await retry(newClient, {
78+
retries: 50,
79+
minTimeout: 0,
80+
factor: 1.3,
81+
});
82+
83+
return client;
84+
85+
async function newClient() {
86+
const client = new Client(configurations);
87+
await client.connect();
88+
return client;
89+
}
90+
}
5591
}
5692

5793
export default Object.freeze({
5894
query,
59-
getNewConnectedClient,
95+
getNewClient,
6096
});

infra/migrator.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const defaultConfigurations = {
1010
};
1111

1212
async function listPendingMigrations() {
13-
const databaseClient = await database.getNewConnectedClient();
13+
const databaseClient = await database.getNewClient();
1414

1515
try {
1616
const pendingMigrations = await migrationRunner({
@@ -28,7 +28,7 @@ async function listPendingMigrations() {
2828
}
2929

3030
async function runPendingMigrations() {
31-
const databaseClient = await database.getNewConnectedClient();
31+
const databaseClient = await database.getNewClient();
3232

3333
try {
3434
const migratedMigrations = await migrationRunner({

models/health.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ async function getDependencies() {
3030
async function checkDatabaseDependency() {
3131
let result;
3232
try {
33-
const maxConnectionsResult = await database.query('SHOW max_connections');
33+
const maxConnectionsResult = await database.query(
34+
'SELECT datconnlimit as max_connections FROM pg_database WHERE datname = $1',
35+
[process.env.POSTGRES_DB]
36+
);
3437
const maxConnectionsValue = maxConnectionsResult.rows[0].max_connections;
3538

3639
const openConnectionsResult = await database.query(

tests/orchestrator.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ async function waitForAllServices() {
3838
if (tries >= 25) {
3939
console.log(`> Trying to connect to Database #${tries}. Are you running the Postgres container?`);
4040
}
41-
const connection = await database.getNewConnectedClient();
41+
const connection = await database.getNewClient();
4242
await connection.end();
4343
},
4444
{
@@ -69,7 +69,7 @@ async function waitForAllServices() {
6969
}
7070

7171
async function dropAllTables() {
72-
const databaseClient = await database.getNewConnectedClient();
72+
const databaseClient = await database.getNewClient();
7373
await databaseClient.query('drop schema public cascade; create schema public;');
7474

7575
await databaseClient.end();

0 commit comments

Comments
 (0)