Repository navigation
noded: a log chunk's job record counts the log it was read from - #48
Merged
Merged
Conversation
thousands_of_held_reads_wait_on_one_watch_and_disconnects_free_them failed in CI with a read answering stdout_bytes 0 after the one-byte append. Held reads do not return early: a logs read wakes on the append, re-reads and returns because its chunk is non-empty. But read_pass built the record first (StateDir::record sizes the running job's logs by opening them) and then opened the stream's log again for the chunk. An append landing between the two opens (the appender's create and write straddle the woken re-reads) produced a chunk with the new byte next to a record that still said 0. Status reads take their cursor and counts from one record, so they cannot show this. Reproduced locally: under load the instrumented test showed a logs read answering data "eA==", next_offset 1, job.stdout_bytes 0; a scratch route test reading logs while a thread appends saw 321 of 3000 chunks run past their record before this change and none after. The record a chunk carries now takes the stream's count from the size the chunk was read against (JobRecord::read_against) while the job runs; once terminal the persisted counts stand. The state is still read before the log, so a terminal record never undercounts a final log. Production impact: no spurious early returns for clients long-polling status or logs. A running job's logs response could carry a job record (stdout_bytes/stderr_bytes, cursor) older than its own data, and the gateway cached that record as the job's state; the counts are a lower bound, so cached answers during lifecycle transitions were at worst stale, not wrong. The SDK does not read the record from log chunks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
rlrs
force-pushed
the
fix/noded-held-read-early-return
branch
from
October 24, 2026 12:23
b32dffc to
02cef28
Compare
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.
thousands_of_held_reads_wait_on_one_watch_and_disconnects_free_themfailed in CI: one read answered withstdout_bytes0 after the one-byte append.Root cause
Held reads do not return early. The bug is in what a logs read sends back.
read_passbuilt the job record first (StateDir::recordopens the running job's logs to get their sizes) and then opened the stream's log a second time to read the chunk. If an append landed between the two opens, the chunk held the new byte while the record still said 0. In the test, the appender's create and write overlap the woken re-reads, so this can happen. Status reads take their cursor and counts from a single record, so they can't show this.Reproduced locally:
data "eA==", next_offset 1, job.stdout_bytes 0.Fix
The record a chunk carries now takes the stream's count from the size the chunk was read against (
JobRecord::read_against) while the job runs. Once the job is terminal, the persisted counts stand. The state is still read before the log, so a terminal record never undercounts a final log.Production impact
stdout_bytes/stderr_bytes,cursor) older than its own data, and the gateway cached that record as the job's state. The counts are a lower bound, so cached answers during lifecycle transitions could be stale but not wrong.Tests
a_chunks_record_counts_the_log_it_was_read_from(jobs/files.rs).cargo test --locked --manifest-path runtime/noded/Cargo.tomlpasses.scripts/check_test_rules.pyis clean.🤖 Generated with Claude Code