Skip to content

fix(server): heartbeat the job-log follow stream; fix CLI drop message#152

Merged
Sootopolis merged 1 commit into
mainfrom
wip
Jul 6, 2026
Merged

fix(server): heartbeat the job-log follow stream; fix CLI drop message#152
Sootopolis merged 1 commit into
mainfrom
wip

Conversation

@Sootopolis

Copy link
Copy Markdown
Owner

What

Long CLI jobs that go silent for >50s (e.g. History Phase 3 between per-line output) dropped their /api/jobs/{id}/logs follower with lost connection ... is a server running? start one with 'ccas serve' — even though the detached job kept running and completed normally. The follow stream only carried bytes when a log line landed, so a silent stretch idled the connection past zio-http's 50s idle timeout.

  • Server heartbeat: JobLogStream.withKeepAlive interleaves a 20s keepalive tick into the log stream via mergeHaltLeft, so bytes always flow under the 50s window while the stream still closes the instant the tail ends (the "close = job done" contract holds). Applied only at the /logs route boundary — FileTail/logStream stay pure.
  • Honest drop message: CcasApiClient.streamLines filters the keepalive sentinel back out, and a connected flag splits a never-reached-server failure (cannot reach ... 'ccas server up') from a drop after a 200 (StreamDropped). JobFollower renders the latter as "the job keeps running on the server — reattach with 'ccas logs '". Stale 'ccas serve''ccas server up'.
  • Bonus: a drop now returns an exit code instead of raising, so a batch history --all no longer aborts the remaining clubs when one club's follow drops.

Fixes

Fixes #150.

Testing

  • sbt test — 1018 passed, 0 failed (also run as the pre-push hook).
  • New TestJobLogStream (TestClock, deterministic): keepalive fires during a silent gap; stream halts when its source completes.
  • New TestJobFollower case: a mid-stream StreamDropped yields exit 1 + the ccas logs <id> reattach hint (asserted via TestConsole.outputErr).
  • TestCcasApiClient never-connected wording updated; existing /logs route + FileTail/JobRunner suites unchanged and green.

🤖 Generated with Claude Code

https://claude.ai/code/session_01C1MjcEkHTAmy6fDcnaxuC6

A long CLI job that goes silent for >50s (e.g. History Phase 3) idled the
`/api/jobs/{id}/logs` follow connection past zio-http's 50s idle timeout, so
the follower dropped with "lost connection ... is a server running? start one
with 'ccas serve'" — even though the detached job kept running server-side and
completed normally. The stream only carried bytes when a log line landed, so
any silent stretch left the connection idle.

Server now interleaves a 20s keepalive tick into the log stream
(`JobLogStream.withKeepAlive`, `mergeHaltLeft` so the stream still closes the
moment the tail ends — "close = job done" holds); the follower filters the
keepalive sentinel back out. Bytes always flow well under the 50s window.

The client also stopped lying about the cause: a `connected` flag splits a
never-reached-server failure (kept as `cannot reach ... 'ccas server up'`) from
a drop after a 200 (`StreamDropped`), which `JobFollower` renders as "the job
keeps running on the server — reattach with 'ccas logs <id>'". Stale
`'ccas serve'` wording is corrected to `'ccas server up'` throughout. Because a
drop now returns an exit code instead of raising, a batch `history --all` no
longer aborts the remaining clubs when one club's follow drops.

Fixes #150.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C1MjcEkHTAmy6fDcnaxuC6
@Sootopolis Sootopolis merged commit 9a8bb27 into main Jul 6, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Log-follow stream drops on >50s log-silent gap; CLI misreports it as "server down"

1 participant