fix(line): preserve webhook events through dispatch failures#109655
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 33f340a4f7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| onTurnAdopted: async () => { | ||
| await deliveryControl.onTurnAdopted?.(); | ||
| turnAdopted = true; | ||
| }, |
There was a problem hiding this comment.
Thread adoption through the supported lifecycle
When a LINE turn is durably adopted, this callback is never invoked because channel.inbound.run only threads turnAdoptionLifecycle.onAdopted into reply options (see src/channels/turn/types.ts and src/channels/turn/kernel.ts), not an onTurnAdopted top-level property. In any accepted webhook where the agent run is adopted and then the gateway crashes or dispatch fails before processMessage returns, the spool row remains claimed/pending and is later retried, so the same LINE event can launch a duplicate turn or duplicate reply-token side effects instead of completing at the intended adoption boundary.
Useful? React with 👍 / 👎.
33f340a to
74b3fd3
Compare
Co-authored-by: NianJiuZst <[email protected]>
Co-authored-by: NianJiuZst <[email protected]>
Co-authored-by: NianJiuZst <[email protected]>
74b3fd3 to
85ebedf
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 85ebedf16e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| turnAdoptionLifecycle: { | ||
| admission: "exclusive", | ||
| onAdopted: async () => { | ||
| await deliveryControl.onTurnAdopted?.(); | ||
| turnAdopted = true; | ||
| }, | ||
| ...(deliveryControl.abortSignal ? { abortSignal: deliveryControl.abortSignal } : {}), | ||
| }, |
There was a problem hiding this comment.
Hold claims until deferred turns are admitted
When core.channel.inbound.run defers a LINE turn into the follow-up queue because the reply lane is busy, it can return without calling this onAdopted; the follow-up queue is process-local (src/auto-reply/reply/queue/state.ts), and its durable-ingress handoff relies on onDeferred/onAbandoned plus a later onAdopted. Because this lifecycle only supplies onAdopted, the spool falls through to its implicit queue.complete() path after the enqueue, tombstoning the durable LINE event before the queued turn is admitted, so a Gateway crash or queue drop in that window loses the webhook instead of retrying it.
Useful? React with 👍 / 👎.
|
Merged via squash.
|
…w#109655) * test(line): remove obsolete replay-cache coverage * fix(line): durably spool webhook events Co-authored-by: NianJiuZst <[email protected]> * test(line): tighten webhook spool lifecycle proof * fix(line): use canonical turn adoption lifecycle Co-authored-by: NianJiuZst <[email protected]> * refactor(line): keep spool types private Co-authored-by: NianJiuZst <[email protected]> --------- Co-authored-by: NianJiuZst <[email protected]>
Related: #108411
Reworks #102141 with contributor credit preserved for @NianJiuZst.
AI-assisted maintainer rework approved by Peter.
What Problem This Solves
Fixes an issue where LINE users could lose inbound webhook events when OpenClaw acknowledged the HTTP request before dispatch had durably succeeded. LINE redelivery is optional and not guaranteed, so dispatch failures or a gateway restart could silently drop an accepted event.
Why This Change Was Made
LINE now persists each webhook event in the shared SQLite ingress queue before returning HTTP 200, matching the channel-owned spool pattern used by Telegram. A bounded worker drains per-conversation lanes through the existing LINE bot/monitor path, persists retry and typed dead-letter state, recovers stale claims after restart, and completes the row at the existing durable turn-adoption boundary. No LINE-specific public callback or configuration surface was added.
User Impact
Accepted LINE events now survive gateway restarts and transient dispatch failures. Poison events retry a bounded number of times and become explicit typed dead letters instead of disappearing or retrying forever. Duplicate delivery side effects are prevented once reply-token or turn-adoption side effects commit.
Evidence
Co-authored-by: NianJiuZst [email protected]