Skip to content

fix(rivetkit-core): close drained connections with ws.going_away - #5867

Open
eersnington wants to merge 1 commit into
fix/gateway-close-without-envoy-ackfrom
fix/drain-going-away-close-reason
Open

eersnington wants to merge 1 commit into
fix/gateway-close-without-envoy-ackfrom
fix/drain-going-away-close-reason

Conversation

@eersnington

@eersnington eersnington commented Oct 12, 2026 •

Copy link
Copy Markdown
Member

On a runner drain, the actor closed client WebSockets with code 1000 and no reason. Clients could not tell a drain from a normal close, so in-flight actions rejected with an unstructured error.

  • ActorContext::disconnect_transport_only in rivetkit-rust/packages/rivetkit-core/src/actor/connection.rs closes with the ws.going_away reason once the actor has started to shut down (actor_aborted()).
  • The transport close in rivetkit-rust/packages/rivetkit-core/src/registry/websocket.rs sends code 1001 for that reason. Other closes keep 1000.
  • Clients already classify ws.going_away as reconnect-only (rivetkit-typescript/packages/rivetkit/src/client/lifecycle-errors.ts).
  • The close still happens after the onDisconnect hook, so the hook runs once.
  • Adds tests/driver/actor-conn-drain.test.ts, which drains a runtime and checks that the client gets ws.going_away and onDisconnect runs once. The driver runtime fixture drains on SIGTERM when RIVETKIT_TEST_DRAIN_ON_SIGTERM=1.
let reason = if self.actor_aborted() {
	Some(WS_GOING_AWAY_CLOSE_REASON.to_owned())
} else {
	None
};

This is part 3 of 6 in a stack:

@claude

claude Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Review of PR 5867

The change is small and focused, and it matches the repo conventions. I found no blocking issues. Nothing was compiled or run.

Notes

  1. Public disconnect APIs now share the drain behavior. disconnect_transport_only (actor/connection.rs) also backs the public ActorContext::disconnect_conn and disconnect_conns (actor/context.rs:1273-1281). Any user-initiated disconnect that happens once actor_aborted() is true now closes with 1001 and ws.going_away. That is probably fine, since the actor is going away anyway. If you want only the drain path to use it, the reason could be passed in explicitly instead of read from actor_aborted().

  2. The 1000 to 1001 mapping depends on a string match. In registry/websocket.rs the code is chosen by comparing the reason string to WS_GOING_AWAY_CLOSE_REASON. The shared constant keeps the two sides in sync, but a typed close-code argument on the disconnect callback would be sturdier. Optional.

  3. Test fixture.

    • The onDisconnect sleep of 100ms is a timing-based way to provoke a duplicate hook run, so the test can pass without exercising the race if the timing shifts.
    • Counting hook runs by splitting captured stdout is fragile and depends on getRuntimeOutput being available. If it is undefined, the ?? "" fallback gives hookRuns === 0 and the test fails with a misleading message.
    • The test only covers the native runtime, the bare encoding and the local SQLite backend. The wasm path is not covered.
  4. Test runtime. process.once("SIGTERM", () => void nativeRegistry.shutdown()) discards the promise, so a shutdown failure becomes an unhandled rejection. Adding a .catch that logs and exits non-zero would make failures easier to diagnose.

  5. Tests and style. There is no Rust test for the new code, such as a unit test of the reason-to-code mapping or of disconnect_transport_only with actor_aborted() set. Per CLAUDE.md, any Rust test should live under tests/. The import ordering in registry-static.ts (conn-drain after conn-error-serialization) is slightly off alphabetically, which is a nit.

Good: the close still happens after the onDisconnect hook, so the hook runs once, and clients already treat ws.going_away as reconnect-only.

@eersnington
eersnington added this pull request to stack #5872 October 13, 2026 18:06
@eersnington
eersnington force-pushed the fix/drain-going-away-close-reason branch 2 times, most recently from 120df78 to 2b2bdf1 Compare October 13, 2026 21:10
@eersnington
eersnington removed this pull request from stack #5872 October 13, 2026 21:11
@eersnington
eersnington changed the base branch from fix/client-retry-actor-ready-timeout to fix/gateway-close-without-envoy-ack October 13, 2026 21:11
@eersnington
eersnington added this pull request to stack #5875 October 13, 2026 21:11
@eersnington
eersnington force-pushed the fix/drain-going-away-close-reason branch from 2b2bdf1 to adab4ef Compare October 13, 2026 21:18

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