From f1a1032cd652c16f16d1afc030c9d122f5465c70 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 10 Jan 2026 18:05:33 +0100 Subject: [PATCH] fix: serialize telegram media-group processing --- CHANGELOG.md | 1 + src/telegram/bot.ts | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bc163f04..5794c2deb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ - Tests/Agents: add regression coverage for workspace tool path resolution and bash cwd defaults. - iOS/Android: enable stricter concurrency/lint checks; fix Swift 6 strict concurrency issues + Android lint errors (ExifInterface, obsolete SDK check). (#662) — thanks @KristijanJovanovski. - iOS/macOS: share `AsyncTimeout`, require explicit `bridgeStableID` on connect, and harden tool display defaults (avoids missing-resource label fallbacks). +- Telegram: serialize media-group processing to avoid missed albums under load. - Docs: showcase entries for ParentPay, R2 Upload, iOS TestFlight, and Oura Health. (#650) — thanks @henrino3. ## 2026.1.9 diff --git a/src/telegram/bot.ts b/src/telegram/bot.ts index 306a3e87d..f10a42a27 100644 --- a/src/telegram/bot.ts +++ b/src/telegram/bot.ts @@ -238,6 +238,7 @@ export function createTelegramBot(opts: TelegramBotOptions) { }; const mediaGroupBuffer = new Map(); + let mediaGroupProcessing: Promise = Promise.resolve(); const cfg = opts.config ?? loadConfig(); const account = resolveTelegramAccount({ @@ -1228,14 +1229,24 @@ export function createTelegramBot(opts: TelegramBotOptions) { existing.messages.push({ msg, ctx }); existing.timer = setTimeout(async () => { mediaGroupBuffer.delete(mediaGroupId); - await processMediaGroup(existing); + mediaGroupProcessing = mediaGroupProcessing + .then(async () => { + await processMediaGroup(existing); + }) + .catch(() => undefined); + await mediaGroupProcessing; }, MEDIA_GROUP_TIMEOUT_MS); } else { const entry: MediaGroupEntry = { messages: [{ msg, ctx }], timer: setTimeout(async () => { mediaGroupBuffer.delete(mediaGroupId); - await processMediaGroup(entry); + mediaGroupProcessing = mediaGroupProcessing + .then(async () => { + await processMediaGroup(entry); + }) + .catch(() => undefined); + await mediaGroupProcessing; }, MEDIA_GROUP_TIMEOUT_MS), }; mediaGroupBuffer.set(mediaGroupId, entry);