Skip to content

fix(rivetkit): wire CancellationToken through waitForNamesAvailable to eliminate KV busy-polling#5063

Open
abcxff wants to merge 1 commit into
05-14-fix_rivetkit_fix_bigint_serialization_in_inspector_workflow_history_and_state_deserializationfrom
05-18-fix_rivetkit_wire_cancellationtoken_through_waitfornamesavailable_to_eliminate_kv_busy-polling
Open

fix(rivetkit): wire CancellationToken through waitForNamesAvailable to eliminate KV busy-polling#5063
abcxff wants to merge 1 commit into
05-14-fix_rivetkit_fix_bigint_serialization_in_inspector_workflow_history_and_state_deserializationfrom
05-18-fix_rivetkit_wire_cancellationtoken_through_waitfornamesavailable_to_eliminate_kv_busy-polling

Conversation

@abcxff
Copy link
Copy Markdown
Contributor

@abcxff abcxff commented May 18, 2026

Fixes RVT-6297

@railway-app
Copy link
Copy Markdown

railway-app Bot commented May 18, 2026

🚅 Deployed to the rivet-pr-5063 environment in rivet-frontend

Service Status Web Updated (UTC)
kitchen-sink ❌ Build Failed (View Logs) Web May 22, 2026 at 5:08 am
frontend-cloud 😴 Sleeping (View Logs) Web May 21, 2026 at 10:58 pm
website 😴 Sleeping (View Logs) Web May 21, 2026 at 10:33 am
frontend-inspector ❌ Build Failed (View Logs) Web May 19, 2026 at 8:20 pm
mcp-hub ✅ Success (View Logs) Web May 18, 2026 at 5:01 pm
ladle ✅ Success (View Logs) Web May 18, 2026 at 5:01 pm

Copy link
Copy Markdown
Contributor Author

abcxff commented May 18, 2026

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@abcxff abcxff marked this pull request as ready for review May 18, 2026 17:00
@linear
Copy link
Copy Markdown

linear Bot commented May 18, 2026

RVT-6297

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented May 18, 2026

PR Review: fix(rivetkit): wire CancellationToken through waitForNamesAvailable to eliminate KV busy-polling

Summary

This PR replaces a busy-polling loop in waitForNamesAvailable with a properly wired CancellationToken, bringing it into parity with the other queue wait methods (waitForNames, next, nextBatch, enqueueAndWait). The old approach sliced timeouts into 100 ms windows and restarted the call in a loop — a pattern explicitly forbidden by CLAUDE.md ("If it is inside a loop { check; sleep } body, it is polling and should be event-driven instead"). The new approach is correctly event-driven.

Overall this is a good, well-scoped fix. There are two type-safety issues worth addressing.


Bug: NapiCoreRuntime.actorQueueWaitForNamesAvailable omits the asNativeCancellationToken cast

File: rivetkit-typescript/packages/rivetkit/src/registry/napi-runtime.ts, line 684

Every other signal-bearing queue method in NapiCoreRuntime wraps the signal via asNativeCancellationToken() before passing it to the NAPI layer:

// actorQueueNextBatch
signal ? asNativeCancellationToken(signal) : signal,

// actorQueueWaitForNames
signal ? asNativeCancellationToken(signal) : signal,

// actorQueueEnqueueAndWait
signal ? asNativeCancellationToken(signal) : signal,

But the new actorQueueWaitForNamesAvailable passes signal directly without the cast. This breaks the established invariant that the NAPI-facing Queue.waitForNamesAvailable receives a typed NativeCancellationToken, not an opaque CancellationTokenHandle. If the handle representation ever diverges from the NAPI type, this silently passes the wrong object.

Fix:

.waitForNamesAvailable(names, options, signal ? asNativeCancellationToken(signal) : signal);

Consistency: WasmCoreRuntime.actorQueueWaitForNamesAvailable also omits asWasmCancellationToken

File: rivetkit-typescript/packages/rivetkit/src/registry/wasm-runtime.ts, line 770

Same pattern issue on the wasm side. All other signal-bearing wasm queue calls cast the signal explicitly via asWasmCancellationToken(), but the new waitForNamesAvailable passes signal bare to callHandleAsync. Since callHandleAsync calls .apply(handle, args) as-is, there is no implicit cast.

Fix:

await callHandleAsync(queue, "waitForNamesAvailable", names, options, signal ? asWasmCancellationToken(signal) : signal);

Code Quality: Good

  • The deletion of the polling loop (~53 lines) is the main win. The new CancellationToken-based approach is event-driven and consistent with all sibling methods.
  • The try/finally { cleanup?.() } pattern correctly handles the case where cleanup is undefined (no signal provided, or signal already aborted before listener registration).
  • createCancellationTokenHandle correctly cancels immediately when signal.aborted is already true, preserving the pre-existing "check aborted first" behavior.
  • The CoreRuntime interface is correctly updated to include the signal parameter.
  • The Rust core side (queue_wait_opts in queue.rs) was already wired to forward CancellationToken into QueueWaitOpts.signal — this PR correctly completes the end-to-end wiring.

Test Coverage Gap

There are no tests for waitForNamesAvailable with an AbortSignal. The existing actor-queue.test.ts covers signal abort for next and iter but not for waitForNamesAvailable. Since the core purpose of this PR is correct signal propagation, a test that aborts mid-wait and asserts the correct error is thrown would prevent regression. Not a blocker, but worth a follow-up.


CLAUDE.md Compliance

  • No println!/eprintln! — clean.
  • No Mutex<HashMap> — not applicable.
  • No inline #[cfg(test)] blocks — clean.
  • No _ => fall-through in enum matches — not applicable.
  • Conventional commit message format — correct.
  • Change correctly scoped to TS/NAPI layer; actor lifecycle logic remains in rivetkit-core.

Required Changes

  1. napi-runtime.ts: Add asNativeCancellationToken() cast when passing signal to waitForNamesAvailable.
  2. wasm-runtime.ts: Add asWasmCancellationToken() cast for the same reason.

@abcxff abcxff force-pushed the 05-18-fix_rivetkit_wire_cancellationtoken_through_waitfornamesavailable_to_eliminate_kv_busy-polling branch from fea950d to 5e99ca7 Compare May 18, 2026 17:10
@abcxff abcxff force-pushed the 05-14-fix_rivetkit_fix_bigint_serialization_in_inspector_workflow_history_and_state_deserialization branch from d9123c0 to 50b18ec Compare May 18, 2026 17:10
@abcxff abcxff force-pushed the 05-14-fix_rivetkit_fix_bigint_serialization_in_inspector_workflow_history_and_state_deserialization branch from 50b18ec to e7602e1 Compare May 18, 2026 19:23
@abcxff abcxff force-pushed the 05-18-fix_rivetkit_wire_cancellationtoken_through_waitfornamesavailable_to_eliminate_kv_busy-polling branch from 5e99ca7 to 0e4c8f5 Compare May 18, 2026 19:23
Copy link
Copy Markdown
Contributor Author

abcxff commented May 19, 2026

Merge activity

  • May 19, 8:06 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • May 19, 8:08 PM UTC: The Graphite merge of this pull request was cancelled.

@abcxff abcxff force-pushed the 05-14-fix_rivetkit_fix_bigint_serialization_in_inspector_workflow_history_and_state_deserialization branch 2 times, most recently from e64e5c1 to 2be6cad Compare May 19, 2026 20:14
@abcxff abcxff force-pushed the 05-18-fix_rivetkit_wire_cancellationtoken_through_waitfornamesavailable_to_eliminate_kv_busy-polling branch from 0e4c8f5 to 73cbe67 Compare May 19, 2026 20:15
@abcxff abcxff force-pushed the 05-14-fix_rivetkit_fix_bigint_serialization_in_inspector_workflow_history_and_state_deserialization branch from 2be6cad to f359aca Compare May 21, 2026 00:35
@abcxff abcxff force-pushed the 05-18-fix_rivetkit_wire_cancellationtoken_through_waitfornamesavailable_to_eliminate_kv_busy-polling branch from 73cbe67 to 9dc7e20 Compare May 21, 2026 00:35
@abcxff abcxff force-pushed the 05-18-fix_rivetkit_wire_cancellationtoken_through_waitfornamesavailable_to_eliminate_kv_busy-polling branch from 9dc7e20 to 9a50acb Compare May 22, 2026 04:17
@abcxff abcxff force-pushed the 05-14-fix_rivetkit_fix_bigint_serialization_in_inspector_workflow_history_and_state_deserialization branch from f359aca to 7b1acff Compare May 22, 2026 04:17
@abcxff abcxff mentioned this pull request May 22, 2026
11 tasks
@abcxff abcxff force-pushed the 05-18-fix_rivetkit_wire_cancellationtoken_through_waitfornamesavailable_to_eliminate_kv_busy-polling branch from 9a50acb to 8f91d91 Compare May 22, 2026 05:08
@abcxff abcxff force-pushed the 05-14-fix_rivetkit_fix_bigint_serialization_in_inspector_workflow_history_and_state_deserialization branch from 7b1acff to 4a3e9a9 Compare May 22, 2026 05:08
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