Skip to content

fix(gateway): durably hand off restart continuations#70780

Merged
obviyus merged 5 commits into
openclaw:mainfrom
fuller-stack-dev:fix/durable-restart-continuation-final
Apr 25, 2026
Merged

fix(gateway): durably hand off restart continuations#70780
obviyus merged 5 commits into
openclaw:mainfrom
fuller-stack-dev:fix/durable-restart-continuation-final

Conversation

@fuller-stack-dev

@fuller-stack-dev fuller-stack-dev commented Apr 23, 2026

Copy link
Copy Markdown
Member

Summary

  • add a durable session-delivery queue for restart continuations with idempotent enqueue, ack/fail bookkeeping, and startup recovery
  • change restart-sentinel startup handling to enqueue continuation work before deleting the sentinel, then drain the queued item after the restart notice is sent
  • gate startup recovery to entries that predate this gateway boot, so a freshly queued continuation cannot replay ahead of the restart notice
  • fall back to a session-only wake when no outbound route survives reboot
flowchart TD
    A[gateway.restart writes restart sentinel] --> B[gateway boots]
    B --> C[startup reads sentinel]
    C --> D[enqueue continuation in durable session queue]
    D --> E[delete restart sentinel]
    E --> F[send restart notice]
    F --> G[drain queued continuation]
    B --> H[startup recovery scans older queued entries only]
    H --> I[replay pre-existing stuck continuations]
Loading

Testing

  • pnpm test src/gateway/server-restart-sentinel.test.ts src/gateway/server-runtime-services.test.ts src/infra/session-delivery-queue.storage.test.ts src/infra/session-delivery-queue.recovery.test.ts
  • pnpm build
  • git merge main -> already up to date

Notes

  • I started from a fresh worktree based on current upstream/main, fast-forwarded local main to the same SHA, and opened the PR from that branch.
  • The normal staged pnpm check:changed --staged path still fails in clean upstream worktrees on unrelated infra tests (src/infra/git-commit.test.ts, src/infra/host-env-security.test.ts, src/infra/run-node.test.ts, src/infra/update-check.test.ts) that inspect git/worktree behavior. I used the repo's FAST_COMMIT escape hatch only after the targeted restart-continuation tests and full build passed.

@openclaw-barnacle openclaw-barnacle Bot added gateway Gateway runtime size: XL labels Apr 23, 2026
@greptile-apps

greptile-apps Bot commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR introduces a durable file-based session-delivery queue for restart continuations, replacing the previous atomic consumeRestartSentinel (read+delete in one step) with a two-phase flow: enqueue the continuation to disk, delete the sentinel, send the restart notice, then drain the queued item. Crash recovery is handled by a 1.25 s-deferred recoverPendingSessionDeliveries call wired into activateGatewayScheduledServices. The implementation is well-structured with idempotency keys, backoff logic, and at-least-once delivery guarantees; the remaining findings are all P2 style/cleanup issues.

Confidence Score: 5/5

Safe to merge — all findings are P2 style and cleanup suggestions with no correctness impact.

The core durability guarantee (enqueue before sentinel deletion, crash recovery on next startup) is implemented correctly. Idempotency, backoff, ack/fail bookkeeping, and the fallback session-wake path all behave as intended per the tests. The three flagged items are a minor orphaned-.tmp accumulation concern, an inconsistent .catch(() => {}) vs. narrow ENOENT catch for moveSessionDeliveryToFailed, and a repeated pure-function call — none of which affect correctness or the primary user path.

No files require special attention.

Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/infra/session-delivery-queue-storage.ts
Line: 74-81

Comment:
**Orphaned `.tmp` files not cleaned up on crash**

`writeQueueEntry` writes to `${filePath}.${process.pid}.tmp` before renaming. If the process crashes between the `writeFile` and `rename` calls, the `.tmp` file is left on disk indefinitely — `loadPendingSessionDeliveries` only sweeps `.delivered` files, not `.tmp` files. Over repeated crashy restarts (the primary scenario for this queue), these orphaned temporaries accumulate in the queue directory without any cleanup path.

Consider adding a `.tmp` sweep to `loadPendingSessionDeliveries`, or using a suffix pattern that the existing cleanup loop already covers.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: src/infra/session-delivery-queue-recovery.ts
Line: 226-229

Comment:
**Inconsistent error handling for `moveSessionDeliveryToFailed`**

`drainPendingSessionDeliveries` (line 157–163) catches only `ENOENT` from `moveSessionDeliveryToFailed` and rethrows anything else, making I/O errors visible. Here, `.catch(() => {})` silently swallows all errors. If a persistent I/O failure (e.g., a permissions issue on the `failed/` subdirectory) prevents the move, the entry stays in queue at max retries, `skippedMaxRetries` is incremented without any warning, and the silent failure repeats on every subsequent recovery pass. Narrowing the catch to `ENOENT` (consistent with `drainPendingSessionDeliveries`) would surface real filesystem problems without breaking the happy path.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: src/gateway/server-restart-sentinel.ts
Line: 217-244

Comment:
**`resolveQueuedSessionDeliveryContext` called twice per branch**

In both the `systemEvent` branch (lines 220–226) and the routeless `agentTurn` fallback (lines 235–241), `resolveQueuedSessionDeliveryContext(params.entry)` is invoked twice — once in the truthiness check and once to spread the result. The function is pure and cheap, so this is not a correctness concern, but capturing the result in a local variable once per branch would avoid the redundant call and make the conditional clearer.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "fix(gateway): durably hand off restart c..." | Re-trigger Greptile

Comment thread src/infra/session-delivery-queue-storage.ts
Comment thread src/infra/session-delivery-queue-recovery.ts
Comment thread src/gateway/server-restart-sentinel.ts

@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: aa201ee772

ℹ️ 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 src/gateway/server-runtime-services.ts

@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: 99376bc05c

ℹ️ 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 src/infra/session-delivery-queue-storage.ts Outdated
Comment thread src/infra/session-delivery-queue-recovery.ts Outdated

@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: 233e1eaddb

ℹ️ 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 src/gateway/server-runtime-services.ts Outdated
@obviyus obviyus self-assigned this Apr 25, 2026
@obviyus
obviyus force-pushed the fix/durable-restart-continuation-final branch from e665930 to f7550b1 Compare April 25, 2026 06:36

@obviyus obviyus 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.

Verified the restart-sentinel loss window: continuations are durably queued before sentinel deletion, and stale queued work recovers after crashy restarts.

Maintainer follow-up bounded startup recovery to pre-boot queue entries, moved the changelog note to the active Unreleased fixes block, and resolved the current-head review thread.

Local gate: targeted restart/queue tests, pnpm check, pnpm build, and manual linked-CLI sentinel/queue smoke.

@obviyus
obviyus merged commit 3565305 into openclaw:main Apr 25, 2026
65 checks passed
@obviyus

obviyus commented Apr 25, 2026

Copy link
Copy Markdown
Contributor

Landed on main.

Thanks @fuller-stack-dev.

steipete pushed a commit to MonkeyLeeT/openclaw that referenced this pull request Apr 25, 2026
Angfr95 pushed a commit to Angfr95/openclaw that referenced this pull request Apr 25, 2026
ayesha-aziz123 pushed a commit to ayesha-aziz123/openclaw that referenced this pull request Apr 26, 2026
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
globalcaos pushed a commit to globalcaos/tinkerclaw that referenced this pull request May 13, 2026
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 24, 2026
jameslcowan pushed a commit to jameslcowan/openclaw that referenced this pull request Jun 2, 2026
sablehead pushed a commit to sablehead/openclaw that referenced this pull request Jun 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gateway Gateway runtime size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants