Skip to content

[runner] Concurrent turns on one session are not gated at start: parallel sandboxes per session, loser reaped only at the next 30s heartbeat, disconnected turns run headless #5539

Description

@mmabrouk

Characterization (from release QA of feat/sessions-storage-rework, 2026-07-28)

Three related behaviors when two clients drive the SAME session concurrently (local sandbox, single runner replica). These may be acceptable v0 trade-offs; filing so the design intent gets decided explicitly rather than by accident.

  1. No start-time gating. Turn X in flight; turn Y arrives on the same session_id from a second connection. Both run fully in parallel, each in its OWN cold-started local sandbox pointed at the same durable mount path. There is no one-active-turn-per-session gate at start; exclusivity exists only after the fact via the heartbeat.

  2. Loser reaped up to 30s late. X only learns it lost at its next heartbeat (HEARTBEAT_INTERVAL_SECONDS = 30): is_current_turn=false -> cooperative abort, open tool call settled as INTERRUPTED_BY_USER, wire finish with finishReason: "other". Until that beat it burns tokens and sandbox time on work that will be thrown away. Observed abort at exactly T+30.055s after turn start.

  3. Disconnect does not cancel. Closing the losing client's SSE connection mid-stream does not abort its run (session-owned disconnect only flags clientGone). The turn keeps executing with no client watching until the same heartbeat-driven reap.

Follow-on bug filed separately: #5538 (the turn right after a takeover can land on the pool entry mid-teardown and fail with a user-visible internal error).

Good news verified at the same time: the durable record log stayed internally consistent through all of this (no duplicate record ids, strictly monotonic timestamps).

Relevant code: services/runner/src/sessions/alive.ts (heartbeat + interrupted), run-turn.ts abort path, server.ts disconnect handling.

https://claude.ai/code/session_01VhviVuZExGJUnY28mzbPBK

Metadata

Metadata

Assignees

No one assigned

    Labels

    Bug ReportSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions