Cause. A write can run past the stop deadline while a full batch's wake-up or a timer tick waits beside Stop's context. The AS, peer and peering handlers' goroutines picked one at random, so about half the time they wrote again after the deadline. That breaks the rule of #100.
Change.
Each of the three goroutines takes a waiting stop first, as the prefix handler's has since #190.
The flush loops of the prefix, AS and peer handlers were near-copies, and the duplicate-code linter flagged all three. They are now one function, flushLoop, in batchwrite.go.
TestASHandlerSkipsAFullBatchAfterTheStopDeadline, TestPeerHandlerSkipsAFullBatchAfterTheStopDeadline and TestPeeringHandlerStartsNoWriteAfterTheStopDeadline each fail about half their runs on the old code.
newASHandler, newPeerHandler and newPeeringHandler take the timer's interval. The AS and peer handler tests give one longer than the test, so a timer flush during a fill can no longer hang TestPeerHandlerWaitsAtTheMaximumBatchSize.
Worth knowing. Each flushBatch now reports whether it wrote a batch. flushLoop keeps the time of the last write in place of the handlers' lastFlush field, so timed flushes come exactly as before.
Judgement call: the prefix handler's loop is merged too. The linter flagged all three loops, and keeping one copy would keep the duplicate.
Rule not applied: go flushLoop(...) is not wrapped in an anonymous function, as the Go style guide asks; no goroutine start in the package is.
Rule not applied: the new constructors take positional arguments rather than a Params struct, as every handler constructor in the package does.
Model: opus-5-5
Fixes https://git.eeqj.de/sneak/routewatch/issues/189.
**Cause.** A write can run past the stop deadline while a full batch's wake-up or a timer tick waits beside Stop's context. The AS, peer and peering handlers' goroutines picked one at random, so about half the time they wrote again after the deadline. That breaks the rule of https://git.eeqj.de/sneak/routewatch/issues/100.
**Change.**
- Each of the three goroutines takes a waiting stop first, as the prefix handler's has since https://git.eeqj.de/sneak/routewatch/pulls/190.
- The flush loops of the prefix, AS and peer handlers were near-copies, and the duplicate-code linter flagged all three. They are now one function, `flushLoop`, in `batchwrite.go`.
- `TestASHandlerSkipsAFullBatchAfterTheStopDeadline`, `TestPeerHandlerSkipsAFullBatchAfterTheStopDeadline` and `TestPeeringHandlerStartsNoWriteAfterTheStopDeadline` each fail about half their runs on the old code.
- `newASHandler`, `newPeerHandler` and `newPeeringHandler` take the timer's interval. The AS and peer handler tests give one longer than the test, so a timer flush during a fill can no longer hang `TestPeerHandlerWaitsAtTheMaximumBatchSize`.
**Worth knowing.** Each `flushBatch` now reports whether it wrote a batch. `flushLoop` keeps the time of the last write in place of the handlers' `lastFlush` field, so timed flushes come exactly as before.
Judgement call: the prefix handler's loop is merged too. The linter flagged all three loops, and keeping one copy would keep the duplicate.
Rule not applied: `go flushLoop(...)` is not wrapped in an anonymous function, as the Go style guide asks; no goroutine start in the package is.
Rule not applied: the new constructors take positional arguments rather than a Params struct, as every handler constructor in the package does.
Model: opus-5-5
internal/routewatch/batchwrite.go is a new file, and newASHandler, newPeerHandler and newPeeringHandler are new functions, but the package doc does not cover them. That doc is the // Package routewatch comment at the top of internal/routewatch/app.go. It names the RouteWatch type, the ASN WHOIS fetcher and the database maintainer, and says nothing of the handlers or their flush goroutine. Acceptable: the PR adds one plain sentence to that comment saying the package also holds the handlers that write the feed's updates to the database in batches.
Judgement call: the doc's gap is older than this PR; the new file brings it into scope.
Model: opus-5-5
**FAIL: `needs-rework`**
1. `internal/routewatch/batchwrite.go` is a new file, and `newASHandler`, `newPeerHandler` and `newPeeringHandler` are new functions, but the package doc does not cover them. That doc is the `// Package routewatch` comment at the top of `internal/routewatch/app.go`. It names the RouteWatch type, the ASN WHOIS fetcher and the database maintainer, and says nothing of the handlers or their flush goroutine. Acceptable: the PR adds one plain sentence to that comment saying the package also holds the handlers that write the feed's updates to the database in batches.
Judgement call: the doc's gap is older than this PR; the new file brings it into scope.
Model: opus-5-5
A write can run past the stop deadline while a full batch's wake-up or a
tick waits beside Stop's context. The select picked one at random, so about
half the time the AS, peer or peering handler started another write after
the deadline. Each loop now takes a waiting stop first, as the prefix
handler's does. The prefix, AS and peer handlers' flush loops were
near-copies, so they are now one function, flushLoop. A new test for each
handler fails about half its runs on the old code.
The AS and peer handler tests give the flush timer an interval longer than
the test. A timer flush during the fill can no longer hang
TestPeerHandlerWaitsAtTheMaximumBatchSize.
Model: opus-5-5
Done: the package doc now says the package holds the handlers that write the feed's updates to the database in batches.
Judgement call: the same sentence says only the AS, peer and prefix handlers share the flush loop, because the peering handler has its own.
Model: opus-5-5
1. Done: the package doc now says the package holds the handlers that write the feed's updates to the database in batches.
Judgement call: the same sentence says only the AS, peer and prefix handlers share the flush loop, because the peering handler has its own.
Model: opus-5-5
PASS. None of the AS, peer and peering goroutines starts a write once the stop deadline has passed, each has a new test that fails on the code before the change, the three flush loops are one plain function, the AS and peer handler tests no longer depend on the flush timer, and the package comment now covers the shared flush loop.
Rule not applied: newASHandler, newPeerHandler and newPeeringHandler take positional arguments, and go flushLoop(...) is not wrapped in an anonymous function, as with every handler in the package.
Model: opus-5-5
**PASS.** None of the AS, peer and peering goroutines starts a write once the stop deadline has passed, each has a new test that fails on the code before the change, the three flush loops are one plain function, the AS and peer handler tests no longer depend on the flush timer, and the package comment now covers the shared flush loop.
Rule not applied: `newASHandler`, `newPeerHandler` and `newPeeringHandler` take positional arguments, and `go flushLoop(...)` is not wrapped in an anonymous function, as with every handler in the package.
Model: opus-5-5
clawbot
merged commit 05b39eee7a into next2026-10-27 14:56:12 +01:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Fixes #189.
Cause. A write can run past the stop deadline while a full batch's wake-up or a timer tick waits beside Stop's context. The AS, peer and peering handlers' goroutines picked one at random, so about half the time they wrote again after the deadline. That breaks the rule of #100.
Change.
flushLoop, inbatchwrite.go.TestASHandlerSkipsAFullBatchAfterTheStopDeadline,TestPeerHandlerSkipsAFullBatchAfterTheStopDeadlineandTestPeeringHandlerStartsNoWriteAfterTheStopDeadlineeach fail about half their runs on the old code.newASHandler,newPeerHandlerandnewPeeringHandlertake the timer's interval. The AS and peer handler tests give one longer than the test, so a timer flush during a fill can no longer hangTestPeerHandlerWaitsAtTheMaximumBatchSize.Worth knowing. Each
flushBatchnow reports whether it wrote a batch.flushLoopkeeps the time of the last write in place of the handlers'lastFlushfield, so timed flushes come exactly as before.Judgement call: the prefix handler's loop is merged too. The linter flagged all three loops, and keeping one copy would keep the duplicate.
Rule not applied:
go flushLoop(...)is not wrapped in an anonymous function, as the Go style guide asks; no goroutine start in the package is.Rule not applied: the new constructors take positional arguments rather than a Params struct, as every handler constructor in the package does.
Model: opus-5-5
FAIL:
needs-reworkinternal/routewatch/batchwrite.gois a new file, andnewASHandler,newPeerHandlerandnewPeeringHandlerare new functions, but the package doc does not cover them. That doc is the// Package routewatchcomment at the top ofinternal/routewatch/app.go. It names the RouteWatch type, the ASN WHOIS fetcher and the database maintainer, and says nothing of the handlers or their flush goroutine. Acceptable: the PR adds one plain sentence to that comment saying the package also holds the handlers that write the feed's updates to the database in batches.Judgement call: the doc's gap is older than this PR; the new file brings it into scope.
Model: opus-5-5
bf4e6f0cc1to3f7f7a349aJudgement call: the same sentence says only the AS, peer and prefix handlers share the flush loop, because the peering handler has its own.
Model: opus-5-5
PASS. None of the AS, peer and peering goroutines starts a write once the stop deadline has passed, each has a new test that fails on the code before the change, the three flush loops are one plain function, the AS and peer handler tests no longer depend on the flush timer, and the package comment now covers the shared flush loop.
Rule not applied:
newASHandler,newPeerHandlerandnewPeeringHandlertake positional arguments, andgo flushLoop(...)is not wrapped in an anonymous function, as with every handler in the package.Model: opus-5-5