fix(discord): unblock inbound queue after stuck run#88251
Conversation
|
Codex review: needs real behavior proof before merge. Reviewed May 30, 2026, 6:06 AM ET / 10:06 UTC. Summary PR surface: Source +78, Tests +167. Total +245 across 4 files. Reproducibility: yes. from source, but not by live repro in this review. Current Review metrics: none identified. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Proof guidance:
Mantis proof suggestion Risk before merge
Maintainer options:
Next step before merge
Security Review findings
Review detailsBest possible solution: Land a Discord-owned queue watchdog only after it uses a supported timeout resolver path, the replay/overlap semantics are explicitly accepted, and live Discord/Gateway or Mantis proof shows the visible delivery path. Do we have a high-confidence way to reproduce the issue? Yes from source, but not by live repro in this review. Current Is this the best way to solve the issue? No, not as currently implemented. The watchdog direction is plausible, but it must use a supported timeout resolver contract and get maintainer acceptance for consumed-replay and late-overlap semantics. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model gpt-5.5, reasoning high; reviewed against 6804b7cb716b. Label changesLabel justifications:
Evidence reviewedPR surface: Source +78, Tests +167. Total +245 across 4 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
3b51b0d to
ae42c4f
Compare
|
@clawsweeper re-review Updated in
|
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
ae42c4f to
1440ed9
Compare
|
@clawsweeper re-review Updated in
I do not have a safe author-side way to run this patch against a live production Gateway/Discord bot. If maintainers want the requested end-to-end visible proof, please run or trigger a Mantis/maintainer proof lane for: |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
@clawsweeper re-review Updated the PR body at head
I also locally ran the repository proof-policy evaluator against the updated body; it returns |
|
🦞👀 Command router queued. I will update this comment with the next step. Re-review progress:
|
|
Thanks for working on this. I am closing this shape because it reintroduces a Discord-owned full-run timeout in the inbound queue, which conflicts with the current channel lifecycle contract: The default also comes from the global agent timeout, which is 48h at |
Summary
This adds a Discord-specific watchdog around queued inbound message runs so one stuck run cannot indefinitely block later messages for the same Discord session key.
The watchdog mirrors the existing configured agent timeout contract via the typed SDK resolver
resolveAgentTimeoutMs({ cfg }). It does not add a new Discord-specific 30-minute production SLA.Problem
Discord inbound handling serializes work per route/session key. If one queued message run never settles after a stuck agent/tool path, later Discord messages for that same session key remain behind the unresolved queue tail. To users, later messages can look silently dropped because no new automatic agent turn starts.
Manual session injection can still work because it bypasses the Discord inbound run queue.
Root cause
createDiscordMessageRunQueue()delegates tocreateChannelRunQueue(), which serializes per key and intentionally imposes no per-task timeout. A non-settling Discord inbound job can therefore hold the queue tail indefinitely.Fix
Wrap each Discord queued message run in a Discord-owned watchdog tied to the existing agent timeout resolver:
resolveAgentTimeoutMs({ cfg })fromopenclaw/plugin-sdk/agent-runtime;processDiscordMessage;DiscordMessageRunTimeoutError;The focused test hook can still inject a short
runTimeoutMsso the queue-tail behavior is testable without waiting for the real agent timeout.Late completion of the original timed-out job is ignored so replay keys are not committed twice.
Compatibility
The shipped
DISCORD_DEFAULT_INBOUND_WORKER_TIMEOUT_MSexport is preserved as a deprecated compatibility export. Production watchdog behavior no longer uses that constant.Real behavior proof
Behavior addressed: A stuck Discord inbound message run can hold the per-session queue tail forever, so a later same-session Discord message does not get processed. After this patch, the queued run receives an abort signal when the configured agent timeout fires, replay is committed for the timed-out delivery, and the next same-session message can proceed.
Real setup tested: Isolated source checkout for this PR head (
1440ed950a0d) running the real Discord monitor queue implementation (createDiscordMessageRunQueue/createDiscordMessageHandler) under the repository's extension-discord Vitest project. This did not use the production Gateway or production Discord bot token.Exact steps or command run after this patch:
Observed result after fix: The regression suite demonstrates the queue-tail behavior directly: message
m-1starts a Discord run that never resolves, messagem-2is queued for the same session key, the injected watchdog timeout abortsm-1, andm-2is processed instead of remaining stuck behindm-1. The suite also verifies replay protection for duplicatem-1, late resolution of the originalm-1without double-commit/logging, and the default timeout path using the configured agent timeout resolver rather than a new Discord-specific 30-minute production SLA.What was not tested: I did not run this patch against a live production Gateway/runtime or production Discord bot. A maintainer/Mantis Discord live proof would still be valuable for the end-to-end visible-delivery path; I requested that separately in a PR comment.
Replay semantics
A watchdog timeout is treated like a non-retryable consumed inbound delivery. This favors avoiding duplicate processing over replaying a message whose processing state is unknown.
Scope / relation to existing work
This is intentionally narrower than #79562. It does not add queue caps, drop policy, persistence, or global channel queue behavior changes. It only prevents a stuck Discord message run from blocking later same-session Discord inbound messages indefinitely.
Related: #9238, #75346, #29497 / #29532, #79562.
A separate adjacent failure mode can still happen after a stuck run is aborted: session write locks may remain or block later writes, producing
SessionWriteLockTimeoutError. That lock-cleanup/recovery seam is already covered by the session-lock issue/PR cluster (for example #21783, #31489, #86540, #86806) and is intentionally out of scope for this Discord queue-tail PR.Risks / limitations
The watchdog aborts cooperatively. If downstream work ignores abort signals, it may still complete later, so a timed-out run can overlap with a newer same-session run. This is preferred over an indefinite queue stall but is not a hard cancellation mechanism.
The timeout ceiling follows the existing agent timeout resolver. It does not add a new 30-minute production timeout.
Full root
tsc -p tsconfig.json --noEmitwas attempted in an isolated checkout before this revision but hit a Node heap OOM before type diagnostics. The focused Discord queue regression suite and diff check passed on currentorigin/main.Tests
Targeted result: