mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2025-11-29 02:42:51 +00:00
Fix: Graceful Telegram bot shutdown to prevent 409 Conflict
Introduces a `botCancel` context and a global `StopBot()` function to ensure the Telegram bot's Long Polling operation is safely terminated (via context cancellation) before the service restarts. This prevents the "Conflict: another update consumer is running" (409) error upon panel restart. Changes: - Added `botCancel context.CancelFunc` to manage context cancellation. - Implemented global `StopBot()` function. - Updated `Tgbot.Stop()` to call `StopBot()`. - Modified `Tgbot.OnReceive()` to use the new cancellable context for `UpdatesViaLongPolling`.
This commit is contained in:
parent
713a7328f6
commit
9ac8fdf3d3
1 changed files with 38 additions and 2 deletions
|
|
@ -39,6 +39,10 @@ import (
|
|||
|
||||
var (
|
||||
bot *telego.Bot
|
||||
|
||||
// botCancel stores the function to cancel the context, stopping Long Polling gracefully.
|
||||
botCancel context.CancelFunc
|
||||
|
||||
botHandler *th.BotHandler
|
||||
adminIds []int64
|
||||
isRunning bool
|
||||
|
|
@ -306,8 +310,13 @@ func (t *Tgbot) SetHostname() {
|
|||
hostname = host
|
||||
}
|
||||
|
||||
// Stop stops the Telegram bot and cleans up resources.
|
||||
// Stop safely stops the Telegram bot's Long Polling operation.
|
||||
// This method now calls the global StopBot function and cleans up other resources.
|
||||
func (t *Tgbot) Stop() {
|
||||
// Call the global StopBot function to gracefully shut down Long Polling
|
||||
StopBot()
|
||||
|
||||
// Stop the bot handler (in case the goroutine hasn't exited yet)
|
||||
if botHandler != nil {
|
||||
botHandler.Stop()
|
||||
}
|
||||
|
|
@ -316,6 +325,24 @@ func (t *Tgbot) Stop() {
|
|||
adminIds = nil
|
||||
}
|
||||
|
||||
// StopBot safely stops the Telegram bot's Long Polling operation by cancelling its context.
|
||||
// This is the global function called from main.go's signal handler and t.Stop().
|
||||
func StopBot() {
|
||||
if botCancel != nil {
|
||||
logger.Info("Sending cancellation signal to Telegram bot...")
|
||||
|
||||
// Calling botCancel() cancels the context passed to UpdatesViaLongPolling,
|
||||
// which stops the Long Polling operation and closes the updates channel,
|
||||
// allowing the th.Start() goroutine to exit cleanly.
|
||||
botCancel()
|
||||
|
||||
botCancel = nil
|
||||
// Giving the goroutine a small delay to exit cleanly.
|
||||
time.Sleep(1 * time.Second)
|
||||
logger.Info("Telegram bot successfully stopped.")
|
||||
}
|
||||
}
|
||||
|
||||
// encodeQuery encodes the query string if it's longer than 64 characters.
|
||||
func (t *Tgbot) encodeQuery(query string) string {
|
||||
// NOTE: we only need to hash for more than 64 chars
|
||||
|
|
@ -346,7 +373,16 @@ func (t *Tgbot) OnReceive() {
|
|||
Timeout: 30, // Increased timeout to reduce API calls
|
||||
}
|
||||
|
||||
updates, _ := bot.UpdatesViaLongPolling(context.Background(), ¶ms)
|
||||
// updates, _ := bot.UpdatesViaLongPolling(context.Background(), ¶ms)
|
||||
|
||||
// --- GRACEFUL SHUTDOWN FIX: Context creation ---
|
||||
// Create a context with cancellation and store the cancel function.
|
||||
var ctx context.Context
|
||||
ctx, botCancel = context.WithCancel(context.Background())
|
||||
// --------------------------------------------------
|
||||
|
||||
// Get updates channel using the created context. This channel will close when ctx is cancelled.
|
||||
updates, _ := bot.UpdatesViaLongPolling(ctx, ¶ms) // <<<
|
||||
|
||||
botHandler, _ = th.NewBotHandler(bot, updates)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue