Skip to content

fix(telegram): drop pending updates on first poll - #211

Merged
BegoniaHe merged 1 commit into
masterfrom
fix/telegram-drop-pending-updates
Sep 17, 2026
Merged

BegoniaHe merged 1 commit into
masterfrom
fix/telegram-drop-pending-updates

Conversation

@BegoniaHe

Copy link
Copy Markdown
Member

Summary

Telegram polling ingested offline pending updates as live messages. A backlog in one chat could stall that session for about 60 seconds in RateLimitStage and cause the bot to answer stale history. This change drops pending updates on the first start_polling of an adapter instance, and keeps them after an in-process client rebuild.

Related issue

Fixes #210

Root cause

updater.start_polling() did not pass drop_pending_updates. python-telegram-bot defaults to False, so Telegram's 24-hour pending queue was converted into pipeline events. The inbound limiter is per UMO with a 30/60 stall window, so one busy chat's backlog slept on the session lock.

Reproduction

  1. Run a Telegram bot token that has accumulated pending updates (adapter offline, then add it in Dashboard, or restart AstrBot after group traffic).
  2. Observe a burst of historical messages enter the pipeline.
  3. For a single chat over 30 updates, that UMO stalls for about one rate-limit window.

Implementation notes

Do not change RateLimitStage. First successful start_polling uses drop_pending_updates=True; later in-process polling after _recreate_application() uses False so a short network gap can catch up. No new config switch. Process restart still drops backlog.

Validation

uv run ruff format astrbot/core/platform/sources/telegram/tg_adapter.py tests/unit/platform/test_telegram_adapter.py
uv run ruff check astrbot/core/platform/sources/telegram/tg_adapter.py tests/unit/platform/test_telegram_adapter.py
uv run pytest tests/unit/platform/test_telegram_adapter.py::test_telegram_polling_allowed_updates_are_explicit tests/unit/platform/test_telegram_adapter.py::test_telegram_run_rebuilds_application_after_repeated_polling_errors tests/unit/platform/test_telegram_adapter.py::test_telegram_run_rebuilds_fresh_application_after_recreate_init_failure
node node_modules/prettier/bin/prettier.cjs --check --ignore-path .gitignore docs/zh/platform/telegram.md docs/en/platform/telegram.md

Ruff format/check passed. The three polling tests passed. Prettier check passed on the two docs pages. make check and the full blocking pytest suite were not run.

Compatibility and risk

User-visible: messages sent while AstrBot was stopped are no longer processed after process start or first adapter connect. In-process polling recovery still replays the gap. No public API, Dashboard protocol, or OpenAPI change.

Checklist

  • The change is focused and does not include unrelated refactoring.
  • I added or updated a regression test, or explained why a test is not practical.
  • I ran the relevant formatting, lint, build, and test commands.
  • User-visible behavior updates both docs/zh/ and docs/en/ when needed.
  • OpenAPI, generated client, docs/public/openapi.json, and tests change together when routes or schemas change.
  • No secrets committed. Runtime Python deps update pyproject.toml, requirements.txt, and uv.lock together.
  • I did not restore legacy shims, Python <3.14 fallbacks, or upstream publish/docs URLs as fork artifacts.
  • Breaking API or behavior changes use ! and a BREAKING CHANGE: footer.
  • I will not merge this PR myself. Merge needs a human maintainer review plus a separate AI-assisted review (AI_POLICY.md).
  • AI use follows AI_POLICY.md. Keep exactly one author note below. Do not fabricate the other.

Agent note

Goal: stop Telegram startup backlog from stalling the per-UMO inbound limiter and from being answered as live traffic. Touched tg_adapter.py, the polling tests in test_telegram_adapter.py, and both Telegram platform docs. Checks actually run are listed above; full make check / blocking pytest were not. Residual risk: operators who wanted crash-restart catch-up will now drop that backlog by design. Tools: OpenCode / GPT. This write-up is not the required separate AI-assisted review.

Discard Telegram server backlog when an adapter instance first starts
polling so offline history does not flush into the pipeline and stall
the per-session rate limiter. Keep pending updates after an in-process
client rebuild so brief disconnects can catch up.

Fixes #210
AI-Generated: true
Generated-At: 2026-09-17T10:41:59Z

@BegoniaHe BegoniaHe left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI-assisted review

独立于作者 ## Agent note 的评审。未代维护者 Approve,也未合并。

结论:可以合入。 无阻断缺陷。改动范围与 #210 验收标准对齐。

做了什么

  • 对照 master...pr-211 的 4 个文件、Issue #210RateLimitStagePlatformManager.reload()、以及本机 python-telegram-botUpdater.start_polling / _bootstrap
  • 本会话运行:
uv run pytest tests/unit/platform/test_telegram_adapter.py::test_telegram_polling_allowed_updates_are_explicit tests/unit/platform/test_telegram_adapter.py::test_telegram_run_rebuilds_application_after_repeated_polling_errors tests/unit/platform/test_telegram_adapter.py::test_telegram_run_rebuilds_fresh_application_after_recreate_init_failure

3 passed。CI 上 Linux/macOS blocking pytest、coverage、ruff、quality 已绿;评审时 Windows blocking 与部分 runtime job 仍 pending,不作为本会话已验证项。

正确性

根因成立:start_polling() 未传 drop_pending_updates 时 PTB 默认为 False,会把 Telegram 约 24 小时积压灌入 pipeline。默认 platform_settings.rate_limit 为 30/60 + stall,同一 UMO 会持锁睡眠约 60.3s。

实现匹配提案:

  1. 适配器实例首次 start_pollingTrue
  2. 赋值 self._drop_pending_updates = Falseawait start_polling(...) 成功返回之后。PTB 会先 _bootstrap()delete_webhook(drop_pending_updates=...))再标记 ready,因此成功返回意味着积压已经丢弃。
  3. start_polling 抛错时标志仍为 True,外层 except Exception 重建后再丢一次,正确。
  4. _recreate_application() 与异常路径的 _build_application() 都发生在首次成功轮询之后,因此进程内追赶用 False
  5. PlatformManager.reload() 会 terminate 再 new instance,Dashboard 停用/启用与进程重启一样会丢积压;这覆盖 Issue 里「离线后在面板添加适配器」的场景。
  6. Telegram 适配器只有 polling,没有 webhook 第二路径。
  7. 未改 RateLimitStage、其他适配器、OpenAPI。

不需要 BREAKING CHANGE:。先前吞积压是缺陷,不是已文档化的承诺。PR 兼容性段已经写明操作者可见变化。

测试与文档

  • 首次 True / 重建后 False 挂在两条已有重建测试上,契约测试补了 drop_pending_updates=True。够用,不必再加函数。
  • 中英文平台页都写了首次丢弃与进程内追赶。英文「flushed into the pipeline and the per-session rate limiter」稍别扭,中文更准确;不阻断。

残留风险(不阻断)

  1. 首次成功轮询之后,进程一直活着但网络中断很久,恢复时 drop_pending_updates=False。新 Updater 的 offset 会重置,Telegram 服务端未确认队列会整段回放。Issue 明确接受「短缺口追赶」;常见「停机一整晚再启动」仍走新实例 + True。若以后要收紧,应按缺口时长丢弃,而不是再加配置开关。
  2. 文档只写了进程重启丢积压,未写 Dashboard 重载同样丢。行为正确,必要时可补一句。
  3. 没有单独覆盖「首次 start_polling 失败后重试仍为 True」。代码路径是 await 之后才翻转,风险低。

流程

fix(telegram): 标题、Fixes #210、AI footer、单一 ## Agent note 都符合 AI_POLICY.md。人类维护者仍需自己审并决定合并。

@BegoniaHe
BegoniaHe merged commit 98243f6 into master Sep 17, 2026
26 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(telegram): drop pending updates on first poll

1 participant