From ae48a238966a8df1f747f853e9b6463a0482101e Mon Sep 17 00:00:00 2001 From: vchikalkin Date: Fri, 15 Aug 2025 17:45:46 +0300 Subject: [PATCH] refactor: implement Redis singleton pattern for improved connection management; enhance graceful shutdown handling in bot --- apps/bot/src/bot/features/download.ts | 4 ++-- apps/bot/src/index.ts | 25 +++++++++++++++++++++++-- apps/bot/src/utils/redis.ts | 10 +++++++++- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/apps/bot/src/bot/features/download.ts b/apps/bot/src/bot/features/download.ts index 46cac38..5e2cf6b 100644 --- a/apps/bot/src/bot/features/download.ts +++ b/apps/bot/src/bot/features/download.ts @@ -2,7 +2,7 @@ import { type Context } from '../context'; import { logHandle } from '../helpers/logging'; import { TTL } from '@/config/redis'; -import { createRedisInstance } from '@/utils/redis'; +import { getRedisInstance } from '@/utils/redis'; import { validateTikTokUrl } from '@/utils/urls'; import { Downloader } from '@tobyg74/tiktok-api-dl'; import { Composer, InputFile } from 'grammy'; @@ -11,7 +11,7 @@ const composer = new Composer(); const feature = composer.chatType('private'); -const redis = createRedisInstance(); +const redis = getRedisInstance(); feature.on('message:text', logHandle('download-message'), async (context) => { try { diff --git a/apps/bot/src/index.ts b/apps/bot/src/index.ts index 78d6ddf..1436462 100644 --- a/apps/bot/src/index.ts +++ b/apps/bot/src/index.ts @@ -1,16 +1,37 @@ import { createBot } from './bot'; import { env as environment } from './config/env'; import { logger } from './utils/logger'; +import { getRedisInstance } from './utils/redis'; const bot = createBot({ apiRoot: environment.TELEGRAM_API_ROOT, token: environment.BOT_TOKEN, }); +const redis = getRedisInstance(); + +// Graceful shutdown function +async function gracefulShutdown(signal: string) { + logger.info(`Received ${signal}, starting graceful shutdown...`); + + try { + // Stop the bot + await bot.stop(); + logger.info('Bot stopped'); + + // Disconnect Redis + redis.disconnect(); + logger.info('Redis disconnected'); + } catch (error) { + const err_ = error as Error; + logger.error('Error during graceful shutdown:' + err_.message || ''); + } +} + // Stopping the bot when the Node.js process // is about to be terminated -process.once('SIGINT', () => bot.stop()); -process.once('SIGTERM', () => bot.stop()); +process.once('SIGINT', () => gracefulShutdown('SIGINT')); +process.once('SIGTERM', () => gracefulShutdown('SIGTERM')); bot.start({ onStart: ({ username }) => logger.info(`Bot ${username} started`), diff --git a/apps/bot/src/utils/redis.ts b/apps/bot/src/utils/redis.ts index 4a98de9..499b08d 100644 --- a/apps/bot/src/utils/redis.ts +++ b/apps/bot/src/utils/redis.ts @@ -2,7 +2,15 @@ import { env } from '@/config/env'; import { logger } from '@/utils/logger'; import Redis from 'ioredis'; -export function createRedisInstance() { +const instance: Redis = createRedisInstance(); + +export function getRedisInstance() { + if (!instance) return createRedisInstance(); + + return instance; +} + +function createRedisInstance() { const redis = new Redis({ host: env.REDIS_HOST, password: env.REDIS_PASSWORD,