Skip to content

fix(rivetkit-core): tolerate workflow not_configured in inspector init - #5683

Merged
abcxff merged 5 commits into
mainfrom
stack/fix-rivetkit-core-tolerate-workflow-not_configured-in-inspector-init-suvtzrqm
Sep 9, 2026
Merged

fix(rivetkit-core): tolerate workflow not_configured in inspector init#5683
abcxff merged 5 commits into
mainfrom
stack/fix-rivetkit-core-tolerate-workflow-not_configured-in-inspector-init-suvtzrqm

Conversation

@abcxff

@abcxff abcxff commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

No description provided.

@abcxff

abcxff commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

@claude

claude Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Review

This PR has grown substantially since my last pass (now includes generation-scoped actor stops, the inspector UI publish pipeline, serverless runtime mode, and the client abort-signal wiring). Updating my review to cover the full current diff.

New since last review

  1. Possible leaked ActorStopHandle when two stops for different generations race under the same actor id. stop_actor parks a PendingStop in self.pending_stops (an scc::HashMap<String, PendingStop>) in three places: when the actor is still starting (registry/mod.rs:1119), and in the TransitionResult::Vacant branch (registry/mod.rs:1154). scc::HashMap::insert_async returns Err (without overwriting) if the key is already occupied, and all three call sites do let _ = ... insert_async(...), silently discarding that error. If a second stop_actor call for a different generation arrives for the same actor_id while a first stop is already parked (e.g. a retried "Lost" stop for an older generation, or two stale generations queued back-to-back while a new generation is starting), the second insert silently no-ops and its ActorStopHandle is never completed. Per the PR's own comment on the failure-path fix ("the map holds the sender alive, hanging the caller"), that's exactly the failure mode being guarded against elsewhere in this same change — but it's not covered here. Given this PR is explicitly hardening cross-generation stop races, it'd be worth an entry_async-based upsert that completes-and-replaces the previous pending stop (mirroring how the success/failure paths in start_actor already complete a stale pending stop instead of dropping it), plus a regression test with two distinct parked generations.

  2. RuntimeMode::from_env silently falls back to Envoy on an invalid value instead of failing. registry/mod.rs's new RuntimeMode::from_env treats anything other than "serverless" (case-insensitively) as Envoy, including a typo'd RIVETKIT_RUNTIME_MODE. The TypeScript counterpart (getRivetkitRuntimeMode in rivetkit-typescript/.../utils/env-vars.ts) throws RIVETKIT_RUNTIME_MODE env var must be "envoy" or "serverless"; got "..." for any unrecognized value. This is a direct parity gap and also cuts against this repo's "Fail-By-Default Runtime" convention (validate required runtime config and throw with actionable context instead of silently falling through). A user who typos serverless would silently get the persistent-envoy runtime with no indication why their serverless deployment isn't behaving as expected.

  3. No test coverage for the new RuntimeMode / start_serverless / serverless_listener code paths. The generation-stop logic got thorough regression tests (nice work there — the three registry tests covering stale/starting/current-generation stops are exactly the right shape), but the new serverless HTTP listener and runtime-mode selection have none.

Carried over from previous review (still open)

The dedicated workflow_dispatch_result unit tests in tests/registry_http.rs still don't cover the new not_configured branch (dispatch.rs:118). Also still open: is_workflow_not_configured_error matches any actor/not_configured error regardless of component, not just workflow-related ones, so it's broader than the docstring implies — matching on component.starts_with("workflow") would make the intent explicit. Both are cheap to address given the existing test table right next to this code.

Resolved from previous review

The earlier concern about inspector-dist/README.md being deleted as an apparent accident no longer applies — this revision adds it (with a real explanation of the staging flow), which is the right call.

Other notes

  • ActorStopHandle::detached() in envoy-client/src/callbacks.rs is #[doc(hidden)] but not #[cfg(test)]-gated, so it ships as a public (if hidden) constructor in the published crate. That's necessary for it to be usable from rivetkit-core's integration tests, but worth double-checking nothing outside tests reaches for it, since a handle whose completion is silently discarded is a correctness footgun in production code.
  • The client-side abort-signal plumbing (actor-handle.ts/client.ts) is a clean, minimal change: threading the handle-level #signal as a fallback for opts.signal and reusing the existing retryOnLifecycleBoundary/sendHttpRequest signal handling rather than duplicating cancellation logic. Test coverage for pre-aborted and mid-flight abort looks solid.
  • The inspector bundle staging (build.rs, stage-inspector-bundle.mjs, verify-inspector-bundle.mjs) is a well-reasoned fix for the crates.io publish gap, with a sensible three-tier fallback (in-crate staged → monorepo dev build → empty placeholder) and a release-time verification step that checks both packaging and runtime serving.

No security concerns beyond what's noted above (item 1 is a liveness/hang risk, not a security issue).

🤖 Generated with Claude Code

@abcxff
abcxff force-pushed the stack/fix-rivetkit-core-tolerate-workflow-not_configured-in-inspector-init-suvtzrqm branch from e1bf6b0 to ea9019e Compare September 9, 2026 23:11
@abcxff
abcxff force-pushed the stack/fix-rivetkit-core-tolerate-workflow-not_configured-in-inspector-init-suvtzrqm branch from ea9019e to 56600a9 Compare September 9, 2026 23:17
@abcxff
abcxff changed the base branch from stack/feat-rivetkit-rust-select-serverless-vs-envoy-runner-mode-via-rivetkit_runtime_mode-rqvuzoyz to main September 9, 2026 23:18
@abcxff
abcxff changed the base branch from main to stack/feat-rivetkit-rust-select-serverless-vs-envoy-runner-mode-via-rivetkit_runtime_mode-rqvuzoyz September 9, 2026 23:21
@abcxff
abcxff changed the base branch from stack/feat-rivetkit-rust-select-serverless-vs-envoy-runner-mode-via-rivetkit_runtime_mode-rqvuzoyz to main September 9, 2026 23:21
@abcxff
abcxff merged commit 56600a9 into main Sep 9, 2026
4 of 9 checks passed
@abcxff
abcxff deleted the stack/fix-rivetkit-core-tolerate-workflow-not_configured-in-inspector-init-suvtzrqm branch September 9, 2026 23:21
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