Skip to content

Attaching to a large session can stall for ~100 s on the last replay chunk #458

Open

Description

@saucam

What happens

Attaching to a large session sometimes takes about 100 seconds. The history arrives in chunks: the first chunks land in tens of milliseconds, then the client waits about 100 s for the last one.

Why it matters

The session looks empty or frozen to the person attaching (web UI, TUI) for over a minute and a half. It hits large sessions, which are the ones people come back to.

What was seen

During the audits for #457 (lazy session loading), the measurement auditor saw it on main (aed1afb) as well as on the branch, so the branch didn't cause it:

  • An attach to a 5.7 MB / 23 MB session took about 101 s in 2 of 7 benchmark runs.
  • On main: chunks f0 to f4 arrived within 80 ms, and the final 218 KB chunk arrived at 101,929 ms.
  • The final chunk waited on the socket's drain callback, which didn't fire. Something else released it about 100 s later.

What we want

An attach replay finishes as soon as the client can take the data, and never waits on a drain that doesn't come. If the socket is genuinely stuck, the replay should fail visibly rather than stall.


🤖 Implementation context (for agents / maintainers)
  • Where: src/daemon/server.ts around the chunked replay flush (≈ lines 987-997 on aed1afb), which awaits the socket's drain before sending the next chunk.
  • Likely cause: Bun's ServerWebSocket.send backpressure status vs. when drain fires. If the last send returned a backpressure status but the buffer emptied without a drain event (or the wait was armed after it fired), the await only ends when something else (a timeout, the next frame) unblocks it. The ~100 s may match an idle or ping timeout.
  • Reproduction: the auditor's stall.ts (per-frame timing of an attach) against a daemon holding sessions with multi-MB transcripts; repeat attaches until one stalls.
  • Fix direction: re-check getBufferedAmount() on a short timer instead of relying only on drain, or arm the wait before checking the send status; bound the wait and close the socket with a clear code if it never drains.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions