ENG-1113: -f/--follow for sandbox logs (client-side polling)#353
ENG-1113: -f/--follow for sandbox logs (client-side polling)#353davixcky wants to merge 2 commits into
Conversation
The sandbox endpoint is a snapshot, so --follow tails by polling on an interval and advancing sinceTime. Correctness details: - per-container de-dup: multiple containers share one sinceTime per request, so each container is de-duped against its own last-printed timestamp and the next poll uses the oldest per-container high-water mark (no lost/repeated lines). - first poll surfaces selector errors (unknown workload/container/etc.); later transient errors (pod not running yet, restarts) are reported once and retried. - graceful stop on SIGINT/SIGTERM. - rejected with -o json|yaml (streamed plain lines only). Job path unchanged (already streams via SSE). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
e908efb to
814d85c
Compare
go-sdk #90 merged (squash) and its branch was deleted, so pin the released main revision instead of the now-non-canonical generate branch commit. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Code ReviewThoughtful, well-scoped change. Follow is implemented client-side by polling the snapshot endpoint every 2s, advancing A few things worth resolving before merge: Correctness / risks1. Dedup can drop lines when timestamps aren't unique (main risk). The boundary filter is At 1 line/sec (as tested) timestamps are distinct so this never fires — but with bursty logs or coarse server-side timestamp precision (second/ms rather than ns) many lines share a timestamp and lines will be lost at every poll boundary. Worth confirming the endpoint's timestamp precision. Robust fix: remember the set/count of messages seen at exactly the max timestamp and only suppress those, rather than everything 2. Catastrophic duplication if 3. First-poll fail-fast also rejects not-yet-running pods. On Minor / style
TestsNo tests added, and the package has no None of these block the happy path that was tested live, but #1 and #2 are the difference between "works in my test" and "correct under load." Also a reminder to retarget/rebase onto 🤖 Generated with Claude Code |


What
Adds
-f/--followtosignadot logsfor the sandbox path (ENG-1113).Stacked on #351 (ENG-1112) — base is
feat/sandbox-logs; will retarget tomainonce #351 merges.The sandbox-scoped endpoint is a point-in-time snapshot, so follow tails by polling on an interval (2s) and advancing
sinceTime. Native pod-log streaming is a fast-follow (ENG-1115). The job path already streams via SSE and is unchanged.Correctness
sinceTimeper request, so a global high-water mark would drop lines from a lagging container. Instead each container is de-duped against its own last-printed timestamp, and the next poll uses the oldest per-container high-water mark — no lost or repeated lines across multiple containers.-o json|yaml(follow streams plain lines only).Testing (live, local cluster)
Followed a 2-container fork (
app+sidecar, each logging every 1s):-f: 70 lines, 70 unique (0 duplicates), 35[app]+ 35[sidecar], sequential with no gaps.-f -c app→ single container, raw (unprefixed), tails live.-f -o json→Error: --follow cannot be combined with -o json.-f --workload nope→ first poll surfaces400 … workload "nope" not found ….🤖 Generated with Claude Code