mirror of
https://github.com/tiennm99/tiennm99bot.git
synced 2026-10-20 02:18:23 +00:00
fix(server): retry webhook clear on startup past transient empty-body error
Telegram's edge can return an empty body on the first request after a cold container start, failing the single best-effort DeleteWebhook with 'unexpected end of JSON input' and leaving a stale webhook that 409s getUpdates. Retry up to 5 times with a 1s backoff so long polling is reliably unblocked.
This commit is contained in:
1 parent
d4f1bbfc83
commit
60a7aa5836
3 files changed
+70
-6
No files matched your search
+37
-6
@@ -146,12 +146,8 @@ 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. drop_pending_updates=false preserves Telegram's
|
||||
// buffered queue so the poller drains updates that arrived during cutover
|
||||
// (lossless cut).
|
||||
if _, err := b.DeleteWebhook(rootCtx, &bot.DeleteWebhookParams{DropPendingUpdates: false}); err != nil {
|
||||
log.Warn("deleteWebhook failed; getUpdates may 409 if a webhook is still set", "err", err)
|
||||
}
|
||||
// 409 while a webhook is set, so a stuck webhook silently breaks the bot.
|
||||
clearWebhook(rootCtx, b)
|
||||
|
||||
deploynotify.Run(rootCtx, deploynotify.Config{
|
||||
Bot: b,
|
||||
@@ -198,6 +194,41 @@ 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: a transient empty-body decode error
|
||||
// on the first attempt must not leave the bot permanently unable to poll.
|
||||
// DropPendingUpdates=false preserves Telegram's buffered queue so the poller
|
||||
// drains updates that arrived during cutover (lossless cut).
|
||||
func clearWebhook(ctx context.Context, b *bot.Bot) {
|
||||
for attempt := 1; attempt <= webhookDeleteAttempts; attempt++ {
|
||||
_, err := b.DeleteWebhook(ctx, &bot.DeleteWebhookParams{DropPendingUpdates: false})
|
||||
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.
|
||||
|
||||
Reference in new issue
Block a user