Skip to content

Connection perf: coalesce queue claim flow to 1 round trip, cross-service batch, real file-transfer verb #5757

Open

Description

@dezren39

Coalesce queue claim flow + add a real file-transfer verb (fewer round trips, WS-C census)

Part of epic #5412. Census evidence: WS-C comment on #5701 (2026-11-04). Every sandbox↔laptop round trip costs ~200–600 ms warm, so round-trip COUNT is the lever until/unless the multiplexed-tunnel work lands.

Round-trip census today (code + logs)

Operation Transport round trips Wall (measured)
Single trivial exec (laptop-agent.py exec -- true) 1 (unix to session proxy + 1 pooled-tunnel HTTP request) wall 346–719 ms; trip p50 369 ms
fleet queue claim (one claim) 1 (call("/claim") → one broker_roundtrip → one unix_roundtrip; repo-queue crate crates/repo-queue/src/main.rs cmd_claim/call) ~1 trip ≈ 0.3–0.6 s warm
Claimant launch flow (claim + lane + bind) 3 separate CLI invocations = 3 round trips (cmd_lane, cmd_bind are separate call()s) ~1–2 s warm, ×3 failure surfaces
Detached job to completion (run + poll loop) 1 + N polls (poll sleeps 3 s client-side and re-requests per iteration, laptop-agent.py poll) grows with job length
Small file fetch from laptop NO file verb exists: fetch = 1 exec round trip with base64 -w0 in a shell string (measured 301 ms wall for /etc/hostname), 1 MiB/stream cap, +33% base64 size, no resume/offsets 1 trip + encoding overhead

Also measured: fleet queue health took 2.1 s and 5.8 s in two live probes (vs 0.30 s in the #5701 stage-2 window) — it visibly resolves secrets ("resolved via bitwarden") plus queries, i.e. multiple internal round trips; health should be 1 lightweight trip.

Proposal

  1. Batch endpoint for the claim flow: queue-broker POST /claim-flow {queue, worker, lane, session, launched_by} performing claim+lane+bind server-side (laptop-local, Supabase calls stay on the laptop) and returning the bound row. Client fleet queue claim --bind ... uses it when session info is present; the 3 separate verbs remain for compatibility. 3 trips → 1.
  2. Generic batch already half-exists: the daemon /exec accepts cmds: [...] (exec-batch measured: 10 trivial commands in ONE trip, 483 ms wall total vs ~400 ms EACH singly). Publish this pattern to queue/secrets clients: a /batch on the session-proxy protocol that carries several service requests (mixed ports) in one frame and fans out at the broker. Client libraries coalesce independent calls made in one invocation.
  3. File-transfer verb: daemon GET /file?path=&off=&len= returning raw bytes (Content-Type application/octet-stream, byte-range via query — the jobs poll already proves the offset pattern) + client laptop-agent.py fetch PATH OUT. No base64, chunked by offset, resume = re-request from last offset. Binary framing arrives free if the multiplexed-tunnel work (sibling issue) lands; the verb is useful on today's HTTP path too.
  4. Poll backoff: poll interval 3 s fixed → exponential 1 s → 10 s cap with server-side long-poll option (?wait_s=N holds the request until state change or N s), cutting poll trips for long jobs by ~10×.

Acceptance

  • Claim+lane+bind in 1 round trip (verify in trips/broker logs: exactly 1 trip id per flow).
  • laptop-agent.py fetch of a 5 MiB file: byte-identical (md5), no base64, trips = ceil(size/chunk) with chunk ≥ 1 MiB.
  • Long-job poll trips reduced ≥5× at equal completion-detection latency ≤10 s.

Activity

  1. developing-today commented on Nov 5, 2026

    @developing-today
    Contributor
  2. added
    queue/queuedHas a queued task in the Supabase agent queue
    task/triageQueue packet kind: verify, reproduce, and route this item
    on Nov 5, 2026
  3. dezren39 commented on Nov 5, 2026

    @dezren39
    MemberAuthor

    Triage outcome — task 10166 (2026-11-05, lane code-p)

    Verdict: CONFIRMED structurally on current mains — proposal routed as two repo-scoped follow-ups (one set, tracked here). No Drew decision needed; epic #5412 is OPEN.

    Fresh verification (2026-11-05): issue #5757 OPEN, labels task/triage + queue/queued only — no hard-stop labels, one tracking comment only. No duplicate: searches for claim-flow / file-transfer verb return nothing filed.

    Claim-flow (code, pkgs/fleet/crates/fleet-queue/, main 04f78696ab): the client dispatches claim, lane, and bind as three separate commands (client.rs:1328-1330), each its own call() — claim posts to /claim (client.rs:882) — and the broker exposes three separate routes (queue_broker.rs: /claim :382, /lane :393, /bind :402). There is no /claim-flow route. This shift is live evidence: every task worked paid claim + lane as separate round trips. Broker /health is a full handler (:517), consistent with the census's heavyweight-health observation (this shift's health calls also printed the bitwarden resolution line).

    File verb + poll (nix, pkgs/laptop-agent/src/laptop_agent.py, current main): the daemon's GET routes are only /health, /jobs, /jobs/<id> (:420-445) — no /file route exists; POST offers /exec, /jobs, /jobs/<id>/kill. The client poll loop sleeps a fixed 3 s (~/tools/laptop-agent.py:281), matching the census, with no wait_s long-poll parameter on either side.

    Routing (cross-repo set; this issue stays the tracker):

    • Follow-up A (code): POST /claim-flow on the queue-broker performing claim+lane+bind server-side + fleet queue claim --bind client support; the three separate verbs remain. Acceptance = the issue's own: exactly 1 trip id per claim flow in broker logs. This is the fleet's hottest path — every queue task in every lane pays it.
    • Follow-up B (dezren39/darwin-nix): daemon GET /file?path=&off=&len= (raw bytes, offset-chunked) + client fetch (byte-identical, no base64), and poll backoff (exponential 1 s → 10 s cap) with a server-side ?wait_s=N long-poll on the job route. Acceptance = the issue's own md5/≥5× poll-trip criteria.
    • Deferred, explicitly: proposal item 2 (a generic cross-service /batch) — the daemon /exec cmds:[...] batch already exists and no client need beyond the claim flow is demonstrated; revisit only if a second concrete multi-call flow appears. The lightweight-health point folds into follow-up A's broker work as a stretch item, not a separate task.

    agent-note:v1
    {"kind": "triage", "task": 10166, "issue": 5757, "state": "done", "outcome": "confirmed_routed_two_repo_set", "evidence": "client.rs:1328-1330 three separate verbs, broker routes /claim /lane /bind separate, no /claim-flow; nix laptop_agent.py GET routes have no /file; client poll fixed sleep(3) at laptop-agent.py:281"}

  4. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    task/triageQueue packet kind: verify, reproduce, and route this item
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 5, 2026
  5. dezren39 commented on Nov 5, 2026

    @dezren39
    MemberAuthor

    agent-note:v1
    {"kind":"work","task":10494,"issue":5757,"state":"in_progress","outcome":"claimed","evidence":"Open issue verified; no hard-stop labels or overlapping nix implementation. Open PR #1531 is a separate persisted-meta startup fix.","branch":"queue/10494-5757-laptop-agent-file-poll","worktree":"/home/user/git/fleet/10494-5757-laptop-agent-file-poll"}

  6. added
    queue/blockedQueue or user escalation state
    status/blockedQueue or user escalation state
    and removed
    queue/claimedQueue worker lifecycle state
    on Nov 5, 2026
  7. 146 remaining items

  8. dezren39 commented on Nov 6, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

  9. added
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    queue/claimedQueue worker lifecycle state
    and removed
    queue/claimedQueue worker lifecycle state
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Nov 6, 2026
  10. dezren39 commented on Nov 6, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

  11. added
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    and removed
    queue/claimedQueue worker lifecycle state
    on Nov 6, 2026
  12. dezren39 commented on Nov 6, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

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

Metadata

Metadata

Assignees

Labels

queue/parkedQueue task is parked (waiting on CI, time, or an event)status/parkedDeliberately paused with a recorded resume conditionwork/assignedQueue worker lifecycle state

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions