fix(server): heartbeat the job-log follow stream; fix CLI drop message#152
Merged
Conversation
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Long CLI jobs that go silent for >50s (e.g. History Phase 3 between per-line output) dropped their
/api/jobs/{id}/logsfollower withlost 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.JobLogStream.withKeepAliveinterleaves a 20s keepalive tick into the log stream viamergeHaltLeft, 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/logsroute boundary —FileTail/logStreamstay pure.CcasApiClient.streamLinesfilters the keepalive sentinel back out, and aconnectedflag splits a never-reached-server failure (cannot reach ... 'ccas server up') from a drop after a 200 (StreamDropped).JobFollowerrenders the latter as "the job keeps running on the server — reattach with 'ccas logs '". Stale'ccas serve'→'ccas server up'.history --allno 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).TestJobLogStream(TestClock, deterministic): keepalive fires during a silent gap; stream halts when its source completes.TestJobFollowercase: a mid-streamStreamDroppedyields exit 1 + theccas logs <id>reattach hint (asserted viaTestConsole.outputErr).TestCcasApiClientnever-connected wording updated; existing/logsroute +FileTail/JobRunnersuites unchanged and green.🤖 Generated with Claude Code
https://claude.ai/code/session_01C1MjcEkHTAmy6fDcnaxuC6