Skip to content

fix(rivetkit): stop lost actor generations immediately - #5824

Open
abcxff wants to merge 1 commit into
stack/fix-envoy-client-signal-lost-actor-generations-synchronously-ykpvpvyofrom
stack/fix-rivetkit-stop-lost-actor-generations-immediately-opswolsp
Open

abcxff wants to merge 1 commit into
stack/fix-envoy-client-signal-lost-actor-generations-synchronously-ykpvpvyofrom
stack/fix-rivetkit-stop-lost-actor-generations-immediately-opswolsp

Conversation

@abcxff

@abcxff abcxff commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

No description provided.

@abcxff

abcxff commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor Author

@claude

claude Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Review: fix(rivetkit): stop lost actor generations immediately (updated after reading the registry, NAPI, wasm and TS changes)

The design is sound. The lost token is revoked at the storage layer, the actor task aborts on it, and per-generation registry records ((actor_id, generation) keys plus current_generations) keep a lost generation visible until it really finishes. A newer generation marks older ones lost and waits up to 10s, and fails to start rather than overlap a stuck one. on_actor_start_with_lost_signal already exists in envoy-client, so the wiring is consistent.

Possible bugs

  • Stale token in ActorTask. ActorTask::new copies ctx.lost_signal(), but configure_lost_signal replaces the token. In envoy_callbacks.rs it is called right after context creation and before start_actor, so the registry path looks fine. Please add a test pinning that ordering, and cancel the replacement token if the old one was already cancelled.
  • start_actor blocks up to 10s on the error path. When a lost generation fails startup, the callback awaits wait_for_generation_finished() with OLDER_GENERATION_STOP_TIMEOUT before returning. The comment explains why, but confirm this does not stall other start or stop callbacks on the same connection.
  • Equal generations. wait_for_older_generations only compares with < and >. Confirm a duplicate start for the same generation number cannot reach it, or is rejected earlier.
  • Dispatch gap. active_actor routes only to the registered generation. While a newer generation is still starting, requests fail with Stopping or Starting. Confirm that is intended.
  • Wasm gap. sleep.rs documents that wasm work keeps only the deadline policy, so user JS already running when Lost fires is not cancelled. The new CLAUDE.md line says no user hooks run after lost. The preamble and run checks cover new hooks, but scope the CLAUDE.md wording accordingly.
  • is_rollback_statement is exact-match only. ROLLBACK TO sp, ROLLBACK TRANSACTION and /* c */ ROLLBACK are rejected after loss. That fails closed, but check cleanup paths only send a bare ROLLBACK.
  • Wrong error for KV. LegacyActorKv::ensure_not_lost returns SqliteRuntimeError::Closed for a KV write. Use a dedicated error or message.
  • In-flight fencing. Confirm kv_put_fenced drops a write when the token fires after queueing but before send, with a test.
  • Action output after lost. onBeforeActionResponse is skipped for a lost generation, but the computed action output is still returned. Check a superseded generation cannot return a success to the client.

Style and nits

  • context.rs: the // Test shim keeps moved tests... comment now sits above the new GenerationHold doc. Move GenerationHold above it.
  • sqlite/tx.rs: the set_lost_signal doc comment is attached to is_lost. Split them.
  • sqlite/mod.rs: the "recheck after open" block is copy-pasted four times. A helper would remove it.
  • ensure_not_lost and is_lost lock a parking_lot::Mutex per statement. An ArcSwap or a token cloned once avoids the hot-path lock.
  • ensure_preamble_not_lost is duplicated in napi_actor_events.rs and wasm lib.rs. The layer rules want shared logic in rivetkit-core, so consider a core helper that returns the error.
  • registry/mod.rs: newer_generation_exists and older_generation_contexts scan whole maps on every start, which is O(actors). A per-actor index would avoid that if actor counts per runner are large.
  • The PR description is empty. Please add a short bullet summary.

Tests
New tests exist in core tests/registry.rs, sqlite.rs, task.rs and the TS lost-generation tests. Please make sure they cover:

  • Lost fires mid-transaction, and only ROLLBACK succeeds.
  • A lost generation stuck in cleanup past 10s makes the next start fail, and the old record stays until it finishes.
  • Lost escalating a pending graceful stop reports StopCode::Error.
  • A stop parked for an older generation is completed when a newer one registers.
  • Token-adoption ordering.

Any new vi.waitFor in the TS tests needs the adjacent justification comment (pnpm run check:wait-for-comments).

Security
No new trust-boundary concerns. Fencing writes from a superseded generation strengthens the single-writer invariant.

@the-company-company the-company-company Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ No issues found

Reviewed commit 2b3bd85.

@abcxff
abcxff force-pushed the stack/fix-rivetkit-stop-lost-actor-generations-immediately-opswolsp branch from 2b3bd85 to 8d4a713 Compare October 3, 2026 02:05
@abcxff
abcxff force-pushed the stack/fix-envoy-client-signal-lost-actor-generations-synchronously-ykpvpvyo branch from bb0f509 to 14f8833 Compare October 3, 2026 02:05
@abcxff
abcxff force-pushed the stack/fix-rivetkit-stop-lost-actor-generations-immediately-opswolsp branch from 8d4a713 to 6a952ff Compare October 6, 2026 01:29
@abcxff
abcxff force-pushed the stack/fix-envoy-client-signal-lost-actor-generations-synchronously-ykpvpvyo branch from 14f8833 to 5a2d258 Compare October 6, 2026 01:29

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant