fix(gateway): Weixin cron/notification sends recover from iLink 'prepare failed' instead of tripping the rate-limit breaker (#112709, salvage #112713) - #113069
Merged
Conversation
…udget The stale-session fallback in `_send_text_chunk` re-sends without `context_token` via `continue`, which advanced the `for attempt in range(retries + 1)` loop. With `send_chunk_retries=0` (the setting the reporter used to surface the raw iLink error) the re-send never happened: the loop ended with `last_error is None` and `send()` failed with an empty AssertionError. Count only real failures in `attempt` so the tokenless re-send is free; backoff timings and log counters are unchanged. Also documents the `ret=-2 prepare failed` / `unknown error` stale-session behaviour in the Weixin troubleshooting table. Part of #112709
૮ >ﻌ< ა ci reviewran on b5f7a5a — fix(gateway): Weixin media sends honour iLink ret and re-sen debug infoCI timingsCI timings · View report · View jobWall time 6m16s vs 6m8s (+2.2%). 7 job(s) slower, 4 faster, 2 unchanged.
|
… a stale token `_send_file` (send_document / send_image / send_video / send_voice, i.e. the cron `media_files` leg of `_deliver_direct`) awaited the caption and media `sendmessage` calls without reading `ret`/`errcode`. `_api_request` only raises on non-2xx HTTP, so a stale-token `ret=-2 errmsg=prepare failed` (or `errcode=-14`) came back as `success=True` with the token still attached and the attachment silently never arrived — the previous commit's claim that the media path shared `_send_text_chunk`'s `_is_session_expired` handling was wrong; only the text path had it. Apply the same mechanism inline in `_send_file`: check `ret`/`errcode` on every item-list send, re-send once without `context_token` (and drop the cached token) when `_is_session_expired` says so, and raise on any other non-zero response so `_send_file_result` reports the failure. Clearing the token covers both the caption and the media item, and bounds the loop. Also mirrors the `prepare failed` troubleshooting row into the zh-Hans docs. Part of #112709
This was referenced Sep 18, 2026
Closed
Closed
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 cron/notification pushes no longer get circuit-broken when iLink answers
ret=-2 errmsg="prepare failed"— the adapter now treats it as the stale-session signal it is and re-sends without the peer'scontext_token, so the message arrives.gateway/platforms/weixin.py::_is_stale_session_ret— recognisesprepare failedalongsideunknown erroras the stale-session variant of iLink's-2(@KoNit-K, cherry-picked from fix(gateway): retry Weixin prepare failures without token #112713)._send_text_chunkroutes through_is_session_expired; the media send path (_send_file) previously did not readretat all — fixed in b5f7a5a (see Review follow-up).gateway/platforms/weixin.py::_send_text_chunk— the tokenless re-send no longer consumes a retry slot. Withsend_chunk_retries=0(the setting the reporter used to surface the raw error) thecontinueused up the only attempt andsend()failed with an emptyAssertionError;attemptnow counts real failures only. Backoff timings and log counters unchanged.website/docs/user-guide/messaging/weixin.md— troubleshooting row forret=-2 prepare failed/unknown error.test_prepare_failed_retries_without_context_token(contributor, parametrised overret/errcode, asserts the circuit stays closed) andtest_tokenless_resend_does_not_consume_retry_budget.Validation (in-process probe, faked iLink response
{"ret": -2, "errmsg": "prepare failed"},send_chunk_retries=0)origin/main9796235_is_stale_session_ret(-2, None, "prepare failed")FalseTrueadapter.send()success=False,iLink sendmessage rate limited; cooldown active for 30.0s, 1 call withctx-token, circuit open 30 ssuccess=True, calls['ctx-token', None], circuit cooldown0.0{"ret": -2, "errmsg": "frequency limit"}scripts/run_tests.sh tests/gateway/test_weixin.py→ 35 passed;tests/gateway/test_weixin_secret_scope.py tests/gateway/test_weixin_typing.py→ 14 passed.Root cause:
_is_stale_session_retonly acceptederrmsg == "unknown error", so theprepare failedvariant of the stale-context-2fell into the rate-limit branch (_record_rate_limit_event, threshold 1, 30 s cooldown) before the existing tokenless fallback could run.Fixes #112709
Salvages #112713 (@KoNit-K)
Infographic
Review follow-up
gateway/platforms/weixin.py::_send_fileignored iLinkret/errmsg;ret=-2 prepare failedon a cron/notification media attachment reportedsuccess=Truewith no tokenless re-send — confirmed on 516bdba (probe: mocked_api_request→{"ret": -2, "errmsg": "prepare failed"},send_document(..., caption="hi")→success=True, 2 calls, both withcontext_token). Fixed @b5f7a5afa0f89:_send_filenow checksret/errcodeon the caption and media item sends, re-sends once withoutcontext_token(dropping the cached token) via the same_is_session_expiredcheck_send_text_chunkuses, and raises on any other non-zero response so_send_file_resultreturnssuccess=False. Invariant testtest_media_send_reads_ret_and_resends_without_token_on_stale_session(red without the fix). Same probe after the fix:success=False error="iLink sendmessage error: ret=-2 errcode=None errmsg=prepare failed", tokens["ctx-token", None]. The incorrect "one site covers both" sentence above is corrected.website/i18n/zh-Hans/.../messaging/weixin.md, same table).