Skip to content

fix(line): preserve webhook events through dispatch failures#109655

Merged
steipete merged 5 commits into
mainfrom
fix/line-webhook-durable-spool
Jul 17, 2026
Merged

fix(line): preserve webhook events through dispatch failures#109655
steipete merged 5 commits into
mainfrom
fix/line-webhook-durable-spool

Conversation

@steipete

@steipete steipete commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

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]

@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation channel: line Channel integration: line size: XL maintainer Maintainer-authored PR labels Jul 17, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💡 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".

Comment thread extensions/line/src/monitor.ts Outdated
Comment on lines +177 to +180
onTurnAdopted: async () => {
await deliveryControl.onTurnAdopted?.();
turnAdopted = true;
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Badge 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 👍 / 👎.

@steipete
steipete force-pushed the fix/line-webhook-durable-spool branch from 33f340a to 74b3fd3 Compare July 17, 2026 05:00
@steipete
steipete force-pushed the fix/line-webhook-durable-spool branch from 74b3fd3 to 85ebedf Compare July 17, 2026 05:05

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💡 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".

Comment on lines +177 to +184
turnAdoptionLifecycle: {
admission: "exclusive",
onAdopted: async () => {
await deliveryControl.onTurnAdopted?.();
turnAdopted = true;
},
...(deliveryControl.abortSignal ? { abortSignal: deliveryControl.abortSignal } : {}),
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Badge 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 👍 / 👎.

@steipete
steipete merged commit 5199bfa into main Jul 17, 2026
117 checks passed
@steipete
steipete deleted the fix/line-webhook-durable-spool branch July 17, 2026 05:13
@steipete

Copy link
Copy Markdown
Contributor Author

Merged via squash.

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 17, 2026
…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]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: line Channel integration: line docs Improvements or additions to documentation maintainer Maintainer-authored PR size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant