Stopping the server waits for report file writes under way (closes #122)
check / check (push) Canceled after 0s

The report buffer's stop now waits, through a sync.WaitGroup, for
flushLoop and for the write Append starts at 10 MiB before its final
flush. It used to return at once, so the process exiting cut such a
write off and its reports were lost.

A write under way that fails puts its reports back in the buffer, so
the final flush writes them; the stop fails only if that flush fails
too.

Tests hold the periodic write and the one at 10 MiB open in a synctest
bubble and find the stop waiting until each is released; a third makes
the held write fail and finds its report written by the final flush.

Model: opus-5-5
This commit was merged in pull request #138.
This commit is contained in:
2026-10-14 14:47:01 +02:00
parent 580d12a934
commit 2861be1c4d
3 changed files with 232 additions and 22 deletions
+14 -3
View File
@@ -96,6 +96,10 @@ type Buffer struct {
// refuses reports, and the reports of that write wait in buf for
// the next flush.
writeErr error
// writers are the goroutines that write report files: flushLoop,
// and each one Append starts at flushSizeThreshold. OnStop waits
// for them before the final flush.
writers sync.WaitGroup
}
// New creates a Buffer and registers lifecycle hooks to
@@ -147,7 +151,7 @@ func New(
b.mu.Unlock()
go b.flushLoop()
b.writers.Go(b.flushLoop)
return nil
},
@@ -158,7 +162,14 @@ func New(
var err error
b.stopOnce.Do(func() {
// Closing done ends flushLoop after any flush it is
// running. Wait for it and for the writes Append
// started, which the process exiting would cut off;
// one that fails puts its reports back in buf, for the
// final flush to write.
close(b.done)
b.writers.Wait()
err = b.flushLocked()
})
@@ -211,12 +222,12 @@ func (b *Buffer) Append(v any) error {
data := b.drainBuf()
b.mu.Unlock()
go func() {
b.writers.Go(func() {
writeErr := b.writeFile(data)
if writeErr != nil {
b.log.Error("flush reports failed", "error", writeErr)
}
}()
})
return nil
}