fix(weixin_oc): keep a cleared timeout field from disabling the HTTP timeout - #10229
Merged
Soulter merged 1 commit intoSep 27, 2026
Merged
Conversation
Soulter
approved these changes
Sep 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
weixin_oc_long_poll_timeout_msandweixin_oc_api_timeout_msare read with a bareint()inWeixinOCAdapter.__init__, with no lower bound. Both are user-tunable fields —tests/test_weixin_oc_config_metadata.pyasserts they are exactly the two personal-WeChat fields the dashboard exposes — and the dashboard's numeric input writes0when the box is cleared (dashboard/src/components/shared/ConfigItemRenderer.vue:toNumber()mapsparseFloat('')→0).Aiohttp reads
ClientTimeout(total=0)as no timeout at all, so a cleared field silently removes the deadline from every WeChat API call:The consequence is in the receive loop:
_poll_inbound_updates()(astrbot/core/platform/sources/weixin_oc/weixin_oc_adapter.py:1579) issuesgetupdateswithtimeout_ms=self.long_poll_timeout_ms, and the loop is written to survive exactly this case (:1763-1769,except asyncio.TimeoutError: ... retry). With the deadline disabled that branch never fires — one stalled connection parks the coroutine forever and the bot goes quiet without a single log line. Same for_poll_qr_status(:1118).A hand-edited non-numeric value is worse:
int('')raisesValueError: invalid literal for int() with base 10: ''inside the constructor, andPlatformManager.initialize(astrbot/core/platform/manager.py:96-97) flattens that to oneFailed to initialize platform adapterline, so the platform never starts.The repository already refuses both shapes for these very keys —
login_registration.py:32-37routesweixin_oc_api_timeout_ms/weixin_oc_long_poll_timeout_msthrough_int_config(value, default, 1_000)on the QR-login path, and this adapter has its own_get_int_config(key, default, minimum)for its other numeric knobs. Only the constructor reads were left unguarded.Modifications / 改动点
Route the three numeric constructor fields (
weixin_oc_qr_poll_interval,weixin_oc_long_poll_timeout_ms,weixin_oc_api_timeout_ms) through the adapter's existing_get_int_config, with aMIN_TIMEOUT_MS = 1_000floor for the two millisecond fields — the same floorlogin_registration._int_configalready applies to the same keys. Defaults and valid values are unchanged; a0, a negative, or a non-numeric value now falls back instead of disabling the timeout or killing the adapter.This is NOT a breaking change. / 这不是一个破坏性变更。
Screenshots or Test Results / 运行截图或测试结果
New
tests/test_weixin_oc_adapter_timeout_floor.py(7 cases: cleared field →1000, value below the floor →1000, tuned value kept, unset → documented default, non-numeric → default instead of raising, and the value that actually reachesself.client.api_timeout_ms).On
master@69ae35a3(fails before the change):The fifth failure is the crash itself:
After the change:
Adjacent and whole-suite regression, Windows / Python 3.12,
TESTING=true:Lint gate (repo-wide job, pinned version):
Docs
No
docs/zhordocs/enupdate: the two fields keep the same meaning, defaults and unit. This change only rejects the values that the login path already rejects, so no documented behavior moves.Checklist / 检查清单
The boxes below are left unticked on purpose: this patch was prepared by an automated agent session working for the account owner, so the first-person statements are the owner's to confirm, not the agent's. The measured evidence each item would attest to is inline above.
📋 查看中文说明
WeixinOCAdapter.__init__用裸int()读取weixin_oc_long_poll_timeout_ms与weixin_oc_api_timeout_ms,且没有下限。这两项恰好是 Dashboard 对个人微信开放调参的字段(tests/test_weixin_oc_config_metadata.py对此有断言),而 Dashboard 的数字输入框被清空时toNumber()会写入0。aiohttp 把ClientTimeout(total=0)解释为「完全不设超时」,于是长轮询getupdates的超时保护失效:接收循环里except asyncio.TimeoutError的重试分支永远不会触发,一条卡住的连接就能让机器人静默且没有任何日志。若配置被手工写成非数字,int('')会在构造期抛ValueError,PlatformManager.initialize只留一行日志,该平台直接起不来。仓库在扫码登录路径上(login_registration.py:32-37)早已用_int_config(value, default, 1_000)对同样的 key 做了下限保护,本适配器的_get_int_config也给它自己的其他数值项设了下限——只有构造函数这三行漏了。本 PR 让这三行改走同一个 helper,默认值与合法取值均不变。新增 7 条用例:修改前5 failed, 2 passed,修改后7 passed;相关三文件12 passed;Windows 全量3526 passed, 82 skipped;ruff 0.15.22check/format 均通过。检查清单未勾选是因为该补丁由自动化 agent 会话代为准备,第一人称声明需由账号本人确认,实测证据已附于上文。Summary by Sourcery
Keep Weixin OC polling and API timeouts positive and robust against invalid dashboard configuration values.
Bug Fixes:
Enhancements:
Tests: