diff --git a/src/database/PrismaClient.ts b/src/database/PrismaClient.ts index a64c307..fd94632 100644 --- a/src/database/PrismaClient.ts +++ b/src/database/PrismaClient.ts @@ -1,6 +1,7 @@ import { PrismaClient } from '@prisma/client'; import { IDatabaseClient } from '../interfaces'; import { logger } from '../utils'; +import { retryAndBackoff } from '../utils/functions'; export class PrismaDatabaseClient implements IDatabaseClient { private static instance: PrismaDatabaseClient; @@ -23,13 +24,7 @@ export class PrismaDatabaseClient implements IDatabaseClient { } async connect(): Promise { - try { - await this.getClient().$connect(); - logger.info(`Prisma connected successfully! ✅`); - } catch (error) { - logger.error(`Prisma connection failed - ${error} ❌`); - process.exit(1); - } + await retryAndBackoff(() => this.getClient().$connect(), 'Prisma'); } async disconnect(): Promise { diff --git a/src/database/RedisClient.ts b/src/database/RedisClient.ts index 7a5a5df..f5174d6 100644 --- a/src/database/RedisClient.ts +++ b/src/database/RedisClient.ts @@ -2,6 +2,7 @@ import { createClient, RedisClientType } from 'redis'; import { redisUrl } from '../config'; import { IDatabaseClient } from '../interfaces'; import { logger } from '../utils'; +import { retryAndBackoff } from '../utils/functions'; export class RedisDatabaseClient implements IDatabaseClient { private static instance: RedisDatabaseClient; @@ -24,13 +25,7 @@ export class RedisDatabaseClient implements IDatabaseClient { } async connect(): Promise { - try { - await this.getClient().connect(); - logger.info(`Redis connected successfully! ✅`); - } catch (error) { - logger.error(`Redis connection failed - ${error} ❌`); - process.exit(1); - } + await retryAndBackoff(() => this.getClient().connect(), 'Redis'); } async disconnect(): Promise { diff --git a/src/utils/functions.ts b/src/utils/functions.ts new file mode 100644 index 0000000..fb7962a --- /dev/null +++ b/src/utils/functions.ts @@ -0,0 +1,37 @@ +import { logger } from './logger'; + +export async function retryAndBackoff( + fn: () => Promise, + serviceName: string, + maxRetries = 10, + baseDelay = 500, +): Promise { + let attempt = 0; + + while (attempt < maxRetries) { + try { + const result = await fn(); + logger.info(`${serviceName} connected successfully! ✅`); + return result; + } catch (error) { + attempt++; + logger.error( + `${serviceName} connection attempt ${attempt} failed: ${error}`, + ); + + if (attempt >= maxRetries) { + logger.error(`Max retries reached for ${serviceName}. Exiting... ❌`); + process.exit(1); + } + + const delay = baseDelay * Math.pow(2, attempt - 1); + logger.info(`Retrying ${serviceName} in ${delay} ms...`); + await new Promise((resolve) => setTimeout(resolve, delay)); + } + } + + // Will not reach here, just for type safety | TODO: Maybe remove this in the future + throw new Error( + `${serviceName} connection failed after ${maxRetries} retries`, + ); +}