Fix tg bot graceful shutdown

This commit is contained in:
2025-08-14 10:46:06 +03:00
parent a284e3ef29
commit 85db17b131
2 changed files with 40 additions and 12 deletions

View File

@@ -5,7 +5,6 @@ import (
"io" "io"
"log/slog" "log/slog"
"net/http" "net/http"
"os"
"strings" "strings"
"time" "time"
@@ -15,14 +14,27 @@ import (
) )
type TelegramController struct { type TelegramController struct {
// deps
bot *tgbotapi.BotAPI bot *tgbotapi.BotAPI
transcribeService *service.TranscribeService transcribeService *service.TranscribeService
jobRepo contract.TranscriptJobRepository jobRepo contract.TranscriptJobRepository
logger *slog.Logger logger *slog.Logger
// params
updateTimeout int
} }
func NewTelegramController(transcribeService *service.TranscribeService, jobRepo contract.TranscriptJobRepository, logger *slog.Logger) (*TelegramController, error) { type TelegramConfig struct {
botToken := os.Getenv("TELEGRAM_BOT_TOKEN") BotToken string
UpdateTimeout int
}
func NewTelegramController(
config TelegramConfig,
transcribeService *service.TranscribeService,
jobRepo contract.TranscriptJobRepository,
logger *slog.Logger,
) (*TelegramController, error) {
botToken := config.BotToken
if botToken == "" { if botToken == "" {
return nil, &EmptyBotTokenError{} return nil, &EmptyBotTokenError{}
} }
@@ -37,6 +49,7 @@ func NewTelegramController(transcribeService *service.TranscribeService, jobRepo
transcribeService: transcribeService, transcribeService: transcribeService,
jobRepo: jobRepo, jobRepo: jobRepo,
logger: logger, logger: logger,
updateTimeout: config.UpdateTimeout,
} }
return controller, nil return controller, nil
@@ -46,7 +59,7 @@ func (c *TelegramController) Start() {
c.logger.Info("Telegram bot started", "username", c.bot.Self.UserName) c.logger.Info("Telegram bot started", "username", c.bot.Self.UserName)
u := tgbotapi.NewUpdate(0) u := tgbotapi.NewUpdate(0)
u.Timeout = 60 u.Timeout = c.updateTimeout
updates := c.bot.GetUpdatesChan(u) updates := c.bot.GetUpdatesChan(u)
@@ -79,7 +92,7 @@ func (c *TelegramController) Start() {
} }
func (c *TelegramController) Stop() { func (c *TelegramController) Stop() {
c.logger.Info("Telegram bot stopped") c.bot.StopReceivingUpdates()
} }
func (c *TelegramController) handleStartCommand(message *tgbotapi.Message) { func (c *TelegramController) handleStartCommand(message *tgbotapi.Message) {

29
main.go
View File

@@ -30,6 +30,13 @@ import (
sloggin "github.com/samber/slog-gin" sloggin "github.com/samber/slog-gin"
) )
const (
TelegramUpdateTimeout = 10
ServerShutdownTimeout = 5
ForceShutdownTimeout = 20
)
func main() { func main() {
// Создаем структурированный логгер // Создаем структурированный логгер
logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{ logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
@@ -101,8 +108,13 @@ func main() {
// Создаем WaitGroup для ожидания завершения всех воркеров // Создаем WaitGroup для ожидания завершения всех воркеров
var wg sync.WaitGroup var wg sync.WaitGroup
tgConfig := tgcontroller.TelegramConfig{
BotToken: os.Getenv("TELEGRAM_BOT_TOKEN"),
UpdateTimeout: TelegramUpdateTimeout,
}
// Создаем Telegram бот // Создаем Telegram бот
tgController, err := tgcontroller.NewTelegramController(transcribeService, jobRepo, logger) tgController, err := tgcontroller.NewTelegramController(tgConfig, transcribeService, jobRepo, logger)
if err != nil { if err != nil {
logger.Error("Failed to create Telegram controller", "error", err) logger.Error("Failed to create Telegram controller", "error", err)
// Не останавливаем приложение, если Telegram бот не создан // Не останавливаем приложение, если Telegram бот не создан
@@ -113,10 +125,8 @@ func main() {
defer wg.Done() defer wg.Done()
logger.Info("Starting Telegram bot") logger.Info("Starting Telegram bot")
tgController.Start() tgController.Start()
logger.Info("Telegram bot stopped")
}() }()
// Добавляем функцию остановки бота в контекст завершения
defer tgController.Stop()
} }
// Создаем воркеры // Создаем воркеры
@@ -198,8 +208,13 @@ func main() {
<-sigChan <-sigChan
logger.Info("Received shutdown signal, initiating graceful shutdown...") logger.Info("Received shutdown signal, initiating graceful shutdown...")
if tgController != nil {
logger.Info("Shutting down Telegram bot...")
tgController.Stop()
}
// Создаем контекст с таймаутом для graceful shutdown HTTP сервера // Создаем контекст с таймаутом для graceful shutdown HTTP сервера
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 5*time.Second) shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), ServerShutdownTimeout*time.Second)
defer shutdownCancel() defer shutdownCancel()
// Останавливаем HTTP сервер // Останавливаем HTTP сервер
@@ -220,11 +235,11 @@ func main() {
close(done) close(done)
}() }()
// Ждем завершения всех воркеров или таймаута в 10 секунд // Ждем завершения всех воркеров или таймаута
select { select {
case <-done: case <-done:
logger.Info("All workers stopped gracefully") logger.Info("All workers stopped gracefully")
case <-time.After(10 * time.Second): case <-time.After(ForceShutdownTimeout * time.Second):
logger.Warn("Timeout reached, forcing shutdown") logger.Warn("Timeout reached, forcing shutdown")
} }