Skip to content

Opening a thread (thread.visit) waits behind the single SQLite writer and shows "Some requests are slow" (34 s) #30301

Open

Description

@EladCohen08

What happens

Opening a thread sends orchestration.dispatchCommand with thread.visit. That command goes through serverRuntimeStartup.enqueueCommand and waits for the single SQLite writer like any agent write. When one write holds the writer, clicking a thread shows the "Some requests are slow" toast (orchestration.dispatchCommand, waiting longer than 15 s). Nothing the user is waiting on depends on that write. The thread content loads through subscribeThread on the reader path.

Evidence (Linux, Ubuntu 24.04, 15 GB RAM, desktop 0.1.6, statev2.sqlite 5.2 GB, about 15 agent sessions running)

  • ws.rpc.orchestration.dispatchCommand thread.visit took 33,920 ms. All of it was spent in serverRuntimeStartup.enqueueCommand / ThreadMessageIntake.dispatchCommand. A second thread.visit 35 s later took 6,274 ms.
  • The writer was held by one orchestrationV2.EventSink.write with event_count: 1 (a claudeAgent native provider thread) for 38,680 ms. Its sql.transaction had db.lock_wait_ms: 0.019 and its commit event fired at 38,671 ms. About 20 other writers recorded db.lock_owner_at_start.span_id pointing at it, with lock waits of 5–38 s.
  • That transaction has no child spans, because the body runs under withTracerEnabled(false). The trace shows the lock was held for 38 s but not what it was doing.
  • Over 83 dispatches in the retained traces, p50 was 13 ms and p90 296 ms. Only the visits that landed behind a long writer were slow.
  • The machine was under memory pressure: 7–8 GB of swap in use, /proc/pressure/io some avg60 about 14%. That makes each synchronous write slower, but the queueing comes from the design.

Expected

  • thread.visit (and thread.mark-unread) do not block the caller. Fire and forget, or coalesce them in memory and flush later, so marking a thread as seen never waits behind agent writes.
  • Bookkeeping commands like these do not count toward the "Some requests are slow" toast.
  • EventSink.write keeps at least coarse child spans (normalize, append, project, outbox) when tracing is off, so a long writer-lock hold can be traced to a cause.

Related

Activity

  1. EtanHey commented on Nov 8, 2026

    @EtanHey
    Contributor

    Note

    🤖 Claude Opus 5.5 posting on behalf of Etan.

    Same symptom at a much larger scale on 0.1.8-nightly.20261108.4353 (macOS arm64). While one EventSink.providerBatch held the writer permit for 25.5 min, waiting at checkpoint admission, four thread.visit dispatches waited 1,024,584 / 950,872 / 917,281 / 712,825 ms. They completed within a few seconds of each other once the batch committed. Reads stayed fast the whole time. Full trace breakdown: #23482 (comment)

    That fits the point here: opening a thread didn't need that write, but it waited the full 15–17 minutes anyway.

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