Skip to content

Commit e944386

Browse files
committed
refactor(database): database initialization and connection logic to handle errors and retries
1 parent 6d9dbd9 commit e944386

File tree

5 files changed

+53
-20
lines changed

5 files changed

+53
-20
lines changed

src/app.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ async function main() {
66
const botInstance = CopBot.getInstance();
77

88
try {
9-
await ServiceProvider.initialize();
9+
const isInitialDatabase = await ServiceProvider.initialize();
10+
if (!isInitialDatabase) {
11+
logger.error('Failed to initialize the database after several attempts.');
12+
process.exit(1);
13+
}
1014
logger.info('Database initialized.');
1115

1216
await botInstance.initial();
@@ -27,8 +31,9 @@ async function main() {
2731
await shutdown(botInstance);
2832
});
2933

30-
process.on('unhandledRejection', (reason) => {
34+
process.on('unhandledRejection', async (reason) => {
3135
logger.error(`${reason}:`, 'Unhandled Rejection');
36+
await shutdown(botInstance);
3237
});
3338

3439
process.on('uncaughtException', async (err: any) => {

src/database/Client.ts

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,27 @@ export class Client {
66
constructor() {
77
this._connectionPool = new ConnectionPool();
88
}
9-
async initialize() {
10-
await this._connectionPool.connect();
11-
const tablesService = new TablesService(this._connectionPool);
12-
logger.info('Setting up initial tables...');
13-
await tablesService.initialTables();
14-
logger.info('Initial Tables Setup Completed.');
9+
async initialize(): Promise<boolean> {
10+
try {
11+
const isConnected = await this._connectionPool.connect();
12+
if (!isConnected) {
13+
logger.error('Database connection failed.');
14+
return false;
15+
}
16+
const tablesService = new TablesService(this._connectionPool);
17+
logger.info('Setting up initial tables...');
18+
await tablesService.initialTables();
19+
logger.info('Initial Tables Setup Completed.');
1520

16-
logger.info('Seeding tables...');
17-
await tablesService.seedTables();
18-
logger.info('Tables seeded successfully.');
21+
logger.info('Seeding tables...');
22+
await tablesService.seedTables();
23+
logger.info('Tables seeded successfully.');
24+
return true;
25+
} catch (error: any) {
26+
// Log any error that occurs during the initialization process
27+
logger.error(`Error during database initialization: ${error.message}`);
28+
return false;
29+
}
1930
}
2031
getConnectionPool(): ConnectionPool {
2132
return this._connectionPool;

src/database/ConnectionPool.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Pool, PoolClient } from 'pg';
22
import Config from '../config';
3+
import logger from '../utils/logger';
34
export class ConnectionPool {
45
private _pool: Pool;
56
private _isProduction: 'development' | 'production';
@@ -8,19 +9,30 @@ export class ConnectionPool {
89
this._isProduction = Config.environment;
910
this._pool = this.initializePool(connectionString);
1011
}
11-
async connect(): Promise<void> {
12+
async connect(): Promise<boolean> {
1213
try {
1314
const client = await this._pool.connect();
14-
client.release(); // Connection successful
15+
client.release();
16+
logger.info('Database connection successful');
17+
return true;
1518
} catch (error: any) {
1619
console.error('Database connection error:', error.message);
1720
if (error.code === '3D000') {
1821
console.log(`Database does not exist. Creating database ${Config.database.databaseName}...`);
1922
await this.createDatabase();
2023
await this.reinitializePool();
21-
await this._pool.connect();
24+
try {
25+
const client = await this._pool.connect();
26+
client.release();
27+
logger.info('Database connection successful after reinitialization');
28+
return true;
29+
} catch (reconnectError: any) {
30+
console.error('Reconnection failed:', reconnectError.message);
31+
return false;
32+
}
2233
} else {
2334
console.error('Unexpected error connecting to the database:', error);
35+
return false;
2436
}
2537
}
2638
}
@@ -56,8 +68,8 @@ export class ConnectionPool {
5668
connectionString,
5769
ssl: this._isProduction === 'production' ? { rejectUnauthorized: false } : false,
5870
max: 20,
59-
idleTimeoutMillis: 10000,
60-
connectionTimeoutMillis: 5000,
71+
idleTimeoutMillis: 30000, // Increase idle timeout
72+
connectionTimeoutMillis: 10000, // Increase connection timeout
6173
keepAlive: true,
6274
});
6375
}

src/decorators/Database.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export function EnsureUserAndGroup(userSource: 'from' | 'reply' = 'reply') {
4545
await Promise.all([
4646
service.getUserService().then((userService) => {
4747
if (!userService) {
48+
console.error('UserService is unavailable.');
4849
close();
4950
return;
5051
}

src/service/database/ServiceProvider.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,14 @@ export class ServiceProvider {
1515
this._clientInstance = new Client();
1616
}
1717

18-
static async initialize(): Promise<ServiceProvider> {
18+
static async initialize(): Promise<ServiceProvider|null> {
1919
if (!ServiceProvider.instance) {
2020
const instance = new ServiceProvider();
21-
await instance._clientInstance.initialize();
21+
const isInitialized = await instance._clientInstance.initialize();
22+
if (!isInitialized) {
23+
logger.error('Failed to initialize client instance. Returning null.');
24+
return null; // Return null if initialization fails
25+
}
2226
instance._connectionPool = instance._clientInstance.getConnectionPool();
2327
ServiceProvider.instance = instance;
2428
}
@@ -81,15 +85,15 @@ export class ServiceProvider {
8185

8286
for (let attempt = 0; attempt < retries; attempt++) {
8387
try {
84-
logger.info(`Database connection attempt ${attempt + 1}...`, 'Database');
88+
logger.warn(`Database connection attempt ${attempt + 1}...`, 'Database');
8589
return await fn(); // Try executing the provided function
8690
} catch (error: any) {
8791
lastError = error;
8892
logger.warn(`Retry Attempt ${attempt + 1} failed with error: ${error.message || error}.`, 'Database');
8993

9094
if (attempt < retries - 1) {
9195
const backoffTime = delay * Math.pow(2, attempt); // Exponential backoff
92-
logger.info(`Retrying in ${backoffTime}ms...`, 'Database');
96+
logger.warn(`Retrying in ${backoffTime}ms...`, 'Database');
9397
await new Promise((res) => setTimeout(res, backoffTime));
9498
}
9599
}

0 commit comments

Comments
 (0)