From 2722db5429c914a21116274e8d24a6bb738db2ea Mon Sep 17 00:00:00 2001 From: tiennm99 Date: Sun, 28 Jun 2026 22:52:55 +0700 Subject: [PATCH] refactor(server): delete webhook once on startup, no retry The Bot API GET reliably clears the webhook, so the retry loop added for the empty-body POST is no longer needed. One best-effort call; log on failure. --- cmd/server/main.go | 43 ++++++------------------------------------- 1 file changed, 6 insertions(+), 37 deletions(-) diff --git a/cmd/server/main.go b/cmd/server/main.go index 8459cdf..e9c4899 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -146,7 +146,12 @@ func main() { // Clear any webhook left over from the AWS deployment at startup, before the // owner DM and before polling. getUpdates (long polling, below) returns HTTP // 409 while a webhook is set, so a stuck webhook silently breaks the bot. - clearWebhook(rootCtx, cfg.TelegramBotToken) + // Best-effort, one shot: a real failure here is logged, not retried. + if err := telegram.DeleteWebhook(rootCtx, cfg.TelegramBotToken); err != nil { + log.Warn("deleteWebhook failed; getUpdates may 409 if a webhook is set", "err", err) + } else { + log.Info("webhook cleared") + } deploynotify.Run(rootCtx, deploynotify.Config{ Bot: b, @@ -193,42 +198,6 @@ func main() { } } -// webhookDeleteAttempts bounds the startup webhook-clear retries, and -// webhookDeleteBackoff is the wait between them. Telegram's edge sometimes -// returns an empty body on the first request after a cold container start -// ("unexpected end of JSON input"); a short retry rides over that blip so long -// polling is not left blocked by a stale webhook. -const ( - webhookDeleteAttempts = 5 - webhookDeleteBackoff = 1 * time.Second -) - -// clearWebhook deletes any configured webhook so getUpdates (long polling) does -// not 409. It is best-effort but retried so a flaky network does not leave the -// bot permanently unable to poll. Uses telegram.DeleteWebhook (a plain Bot API -// GET) rather than the go-telegram helper, whose empty-multipart POST comes back -// with an empty body in some environments. Pending updates are kept so the -// poller drains the buffered queue for a lossless cutover. -func clearWebhook(ctx context.Context, token string) { - for attempt := 1; attempt <= webhookDeleteAttempts; attempt++ { - err := telegram.DeleteWebhook(ctx, token) - if err == nil { - log.Info("webhook cleared", "attempt", attempt) - return - } - log.Warn("deleteWebhook failed", "attempt", attempt, "err", err) - if attempt == webhookDeleteAttempts { - break - } - select { - case <-ctx.Done(): - return - case <-time.After(webhookDeleteBackoff): - } - } - log.Warn("deleteWebhook still failing after retries; getUpdates may 409 if a webhook is set") -} - // buildProvider picks the storage backend. Selection order: // 1. Explicit KV_PROVIDER env (memory|mongodb) wins. // 2. Auto-detect: MONGO_URL set → mongodb; otherwise memory.