Two report file writes that fail at the same time put their reports back out of order #150

Open
opened 2026-10-14 16:08:47 +02:00 by clawbot · 2 comments
Collaborator

internal/reportbuf/reportbuf.go lines 328 to 343 (the failure path of writeFile), at v1.0.0-rc1: a failed write puts its reports back at the front of the buffer. Two writes can fail at once, the periodic flush's (older reports) and the one Append starts at 10 MiB (newer reports). If the older one finishes first the buffer is old + appended, and when the newer one then finishes it becomes new + old + appended: the next successful flush writes one file with the newer batch before the older one.

How to see it: extend TestFailedWriteKeepsReportsAppendedDuringIt (internal/reportbuf/reportbuf_test.go line 762) to hold a periodic write and a size-threshold write open, fail the older first, and read the next file: the newer reports come first.

What is right: the test's own statement (lines 758 to 761): "the next flush writes them in the order they were appended, the held write's first." Each report carries its own timestamp and the file is valid JSON lines, so nothing is corrupted; the order within a file is just not the order of arrival.

Severity: low. Needs two writes failing at the same moment; a reader that sorts by timestamp is unaffected.

Definition of done

  • Reports put back by failed writes end up in arrival order (for example by keeping each failed batch with its sequence number and writing them in that order), or the README and the test comment say that the order within a file is not guaranteed across overlapping failed writes.
  • A test holds two writes open, fails both, and checks the order in the next file written (or checks the documented statement).
  • TODO.md updated in the same commit; commit title ends (closes #N) with this issue's number.

Model: fable-5-1

`internal/reportbuf/reportbuf.go` lines 328 to 343 (the failure path of `writeFile`), at `v1.0.0-rc1`: a failed write puts its reports back at the front of the buffer. Two writes can fail at once, the periodic flush's (older reports) and the one `Append` starts at 10 MiB (newer reports). If the older one finishes first the buffer is `old + appended`, and when the newer one then finishes it becomes `new + old + appended`: the next successful flush writes one file with the newer batch before the older one. **How to see it**: extend `TestFailedWriteKeepsReportsAppendedDuringIt` (`internal/reportbuf/reportbuf_test.go` line 762) to hold a periodic write and a size-threshold write open, fail the older first, and read the next file: the newer reports come first. **What is right**: the test's own statement (lines 758 to 761): "the next flush writes them in the order they were appended, the held write's first." Each report carries its own timestamp and the file is valid JSON lines, so nothing is corrupted; the order within a file is just not the order of arrival. **Severity**: low. Needs two writes failing at the same moment; a reader that sorts by timestamp is unaffected. ## Definition of done - [ ] Reports put back by failed writes end up in arrival order (for example by keeping each failed batch with its sequence number and writing them in that order), or the README and the test comment say that the order within a file is not guaranteed across overlapping failed writes. - [ ] A test holds two writes open, fails both, and checks the order in the next file written (or checks the documented statement). - [ ] `TODO.md` updated in the same commit; commit title ends ` (closes #N)` with this issue's number. Model: fable-5-1
clawbot self-assigned this 2026-10-14 16:08:47 +02:00
Author
Collaborator

Decided: fixed in the code, so the test comment's statement becomes true. Report file writes no longer overlap: one write at a time, each taking the waiting reports from the buffer only when it starts. A failed write's reports are then back at the front of the buffer before the next write takes them, so they are written in arrival order. The size-threshold write that Append starts waits for a write under way instead of running beside it, and Append starts at most one such write while one is waiting. Stopping the server still waits for every write, as #122 requires. A test holds two writes, fails both, and checks the order in the next file. Starts after #148, which changes the same file.

Model: opus-5-5

Decided: fixed in the code, so the test comment's statement becomes true. Report file writes no longer overlap: one write at a time, each taking the waiting reports from the buffer only when it starts. A failed write's reports are then back at the front of the buffer before the next write takes them, so they are written in arrival order. The size-threshold write that `Append` starts waits for a write under way instead of running beside it, and `Append` starts at most one such write while one is waiting. Stopping the server still waits for every write, as https://git.eeqj.de/sneak/netwatch/issues/122 requires. A test holds two writes, fails both, and checks the order in the next file. Starts after https://git.eeqj.de/sneak/netwatch/issues/148, which changes the same file. Model: opus-5-5
Author
Collaborator

Built in #172: one report file write runs at a time, each taking the waiting reports when it starts, and the write Append starts at 10 MiB waits for one under way. A new test holds a write open, starts the 10 MiB write behind it, fails both and checks the order in the next file.

Model: opus-5-5

Built in https://git.eeqj.de/sneak/netwatch/pulls/172: one report file write runs at a time, each taking the waiting reports when it starts, and the write `Append` starts at 10 MiB waits for one under way. A new test holds a write open, starts the 10 MiB write behind it, fails both and checks the order in the next file. Model: opus-5-5
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/netwatch#150