Only Stop ends the reconnect loop now. When the stream ends any other way, with or without an error, the connected flag goes false, so the health check no longer reports ris_live: ok, and the streamer reconnects with the existing backoff. Before, a response that RIS Live ended normally stopped the loop for good.
When no line arrives for 60 seconds (streamIdleTimeout), the streamer drops the connection and reconnects; each line starts that limit over. The same timer bounds the wait for RIS Live to answer the request, so a server that accepts the connection and never responds is dropped too.
The README's Reconnection note describes both.
Worth knowing:
stream no longer returns nil: a normal end returns errStreamEnded. The existing goroutine-leak test now expects that error instead of nil.
The idle limit and the first backoff delay are now fields on the streamer, set from the existing constants in New, so the new tests can shorten them.
A connection dropped for being idle has lasted more than 30 seconds, so the existing backoff reset applies to it: a silent feed is retried about every 65 seconds. No test covers that 30-second reset; this PR changes only its comment.
The test UPDATE line moved to a constant shared by the old and new tests.
Fixes https://git.eeqj.de/sneak/routewatch/issues/53.
What changed:
- Only `Stop` ends the reconnect loop now. When the stream ends any other way, with or without an error, the connected flag goes false, so the health check no longer reports `ris_live: ok`, and the streamer reconnects with the existing backoff. Before, a response that RIS Live ended normally stopped the loop for good.
- When no line arrives for 60 seconds (`streamIdleTimeout`), the streamer drops the connection and reconnects; each line starts that limit over. The same timer bounds the wait for RIS Live to answer the request, so a server that accepts the connection and never responds is dropped too.
- The README's Reconnection note describes both.
Worth knowing:
- `stream` no longer returns nil: a normal end returns `errStreamEnded`. The existing goroutine-leak test now expects that error instead of nil.
- The idle limit and the first backoff delay are now fields on the streamer, set from the existing constants in `New`, so the new tests can shorten them.
- A connection dropped for being idle has lasted more than 30 seconds, so the existing backoff reset applies to it: a silent feed is retried about every 65 seconds. No test covers that 30-second reset; this PR changes only its comment.
- The test UPDATE line moved to a constant shared by the old and new tests.
- `TODO.md` is left to https://git.eeqj.de/sneak/routewatch/issues/72.
Model: opus-5-5
internal/streamer/streamer_test.go, TestReconnectWhenStreamGoesIdle: every test still passes if the idle timer is never restarted when a line arrives (idleTimer.Reset at internal/streamer/streamer.go:573 removed). The limit would then end every connection after 60 seconds, so the busy live feed would be dropped every minute, with a 5-second gap each time. Acceptable: a test where the server sends lines more often than the limit for several times the limit, and the streamer stays on its first connection.
internal/streamer/streamer.go:447-448: the comment says a stream that lasted more than 30 seconds "received data". With the 60-second idle drop, a connection that received nothing also lasts more than 30 seconds and resets the backoff. README.md:144 (Key Design Patterns, "Reconnection") still describes only the backoff: it does not say that a stream RIS Live ends normally is reconnected, or that 60 seconds without a line drops the connection. Acceptable: the comment and the README bullet say what the code does.
TODO.md: no Completed Steps entry. Every earlier fix on next added its dated entry in the same commit, as the workflow at the top of TODO.md asks. Acceptable: a dated Completed Steps entry for #53 ending (closes #53).
Model: opus-5-5
1. `internal/streamer/streamer_test.go`, `TestReconnectWhenStreamGoesIdle`: every test still passes if the idle timer is never restarted when a line arrives (`idleTimer.Reset` at `internal/streamer/streamer.go:573` removed). The limit would then end every connection after 60 seconds, so the busy live feed would be dropped every minute, with a 5-second gap each time. Acceptable: a test where the server sends lines more often than the limit for several times the limit, and the streamer stays on its first connection.
2. `internal/streamer/streamer.go:447-448`: the comment says a stream that lasted more than 30 seconds "received data". With the 60-second idle drop, a connection that received nothing also lasts more than 30 seconds and resets the backoff. `README.md:144` (Key Design Patterns, "Reconnection") still describes only the backoff: it does not say that a stream RIS Live ends normally is reconnected, or that 60 seconds without a line drops the connection. Acceptable: the comment and the README bullet say what the code does.
3. `TODO.md`: no Completed Steps entry. Every earlier fix on `next` added its dated entry in the same commit, as the workflow at the top of `TODO.md` asks. Acceptable: a dated Completed Steps entry for https://git.eeqj.de/sneak/routewatch/issues/53 ending `(closes #53)`.
Model: opus-5-5
Added TestStreamNotDroppedWhileLinesArrive: the server sends a line every 10 ms for five times a 100 ms limit, then ends the response; the stream must end normally, not as idle. It fails when the idleTimer.Reset line is removed.
The backoff comment now says a stream dropped as idle also resets the backoff; the README Reconnection note now covers the normal end, the 60-second idle drop and the backoff.
1. Added `TestStreamNotDroppedWhileLinesArrive`: the server sends a line every 10 ms for five times a 100 ms limit, then ends the response; the stream must end normally, not as idle. It fails when the `idleTimer.Reset` line is removed.
2. The backoff comment now says a stream dropped as idle also resets the backoff; the README Reconnection note now covers the normal end, the 60-second idle drop and the backoff.
3. `TODO.md` left alone, per the plan at https://git.eeqj.de/sneak/routewatch/issues/72#issuecomment-139587.
Model: opus-5-5
internal/streamer/streamer_test.go: nothing tests the claim, made in the PR body and in the comment at internal/streamer/streamer.go:486-489, that the idle limit also bounds the wait for RIS Live to answer the request. Every test still passes when the idle timer is started only after the response headers arrive. With that change, a server that accepts the connection and never answers holds the streamer forever. TestReconnectWhenStreamGoesIdle sends the headers before it goes quiet, so it never reaches the wait for an answer. Acceptable: a test whose first response never sends headers (the handler only waits for the request to end), in which the streamer reconnects after the idle limit. The existing checkReconnect helper is enough for this.
Model: opus-5-5
1. `internal/streamer/streamer_test.go`: nothing tests the claim, made in the PR body and in the comment at `internal/streamer/streamer.go:486-489`, that the idle limit also bounds the wait for RIS Live to answer the request. Every test still passes when the idle timer is started only after the response headers arrive. With that change, a server that accepts the connection and never answers holds the streamer forever. `TestReconnectWhenStreamGoesIdle` sends the headers before it goes quiet, so it never reaches the wait for an answer. Acceptable: a test whose first response never sends headers (the handler only waits for the request to end), in which the streamer reconnects after the idle limit. The existing `checkReconnect` helper is enough for this.
Model: opus-5-5
Only Stop now ends the reconnect loop. A stream that ends any other way,
with or without an error, marks the feed disconnected and reconnects with
the existing backoff. Before, a response RIS Live ended normally stopped
the loop for good while the health check kept reporting ok.
The streamer also drops the connection when no line arrives for 60
seconds; each line starts that limit over, and it also bounds the wait
for RIS Live to answer. The idle limit and the first backoff delay are
fields so the tests, against a local server, run in well under a second.
The README's Reconnection note describes this behaviour.
Model: opus-5-5
Added TestReconnectWhenServerNeverAnswers: the first response never sends headers and the streamer must reconnect after the idle limit; it fails when the idle timer starts only after the headers arrive.
Also: TestNewStreamer now checks that New sets the idle limit and the first backoff delay from their constants (nothing caught a zero first backoff before); the PR body says which backoff claim no test covers. Rebased onto current next.
Model: opus-5-5
1. Added `TestReconnectWhenServerNeverAnswers`: the first response never sends headers and the streamer must reconnect after the idle limit; it fails when the idle timer starts only after the headers arrive.
Also: `TestNewStreamer` now checks that `New` sets the idle limit and the first backoff delay from their constants (nothing caught a zero first backoff before); the PR body says which backoff claim no test covers. Rebased onto current `next`.
Model: opus-5-5
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 #53.
What changed:
Stopends the reconnect loop now. When the stream ends any other way, with or without an error, the connected flag goes false, so the health check no longer reportsris_live: ok, and the streamer reconnects with the existing backoff. Before, a response that RIS Live ended normally stopped the loop for good.streamIdleTimeout), the streamer drops the connection and reconnects; each line starts that limit over. The same timer bounds the wait for RIS Live to answer the request, so a server that accepts the connection and never responds is dropped too.Worth knowing:
streamno longer returns nil: a normal end returnserrStreamEnded. The existing goroutine-leak test now expects that error instead of nil.New, so the new tests can shorten them.TODO.mdis left to #72.Model: opus-5-5
internal/streamer/streamer_test.go,TestReconnectWhenStreamGoesIdle: every test still passes if the idle timer is never restarted when a line arrives (idleTimer.Resetatinternal/streamer/streamer.go:573removed). The limit would then end every connection after 60 seconds, so the busy live feed would be dropped every minute, with a 5-second gap each time. Acceptable: a test where the server sends lines more often than the limit for several times the limit, and the streamer stays on its first connection.internal/streamer/streamer.go:447-448: the comment says a stream that lasted more than 30 seconds "received data". With the 60-second idle drop, a connection that received nothing also lasts more than 30 seconds and resets the backoff.README.md:144(Key Design Patterns, "Reconnection") still describes only the backoff: it does not say that a stream RIS Live ends normally is reconnected, or that 60 seconds without a line drops the connection. Acceptable: the comment and the README bullet say what the code does.TODO.md: no Completed Steps entry. Every earlier fix onnextadded its dated entry in the same commit, as the workflow at the top ofTODO.mdasks. Acceptable: a dated Completed Steps entry for #53 ending(closes #53).Model: opus-5-5
e8709f790eto26988dec34TestStreamNotDroppedWhileLinesArrive: the server sends a line every 10 ms for five times a 100 ms limit, then ends the response; the stream must end normally, not as idle. It fails when theidleTimer.Resetline is removed.TODO.mdleft alone, per the plan at #72 (comment).Model: opus-5-5
internal/streamer/streamer_test.go: nothing tests the claim, made in the PR body and in the comment atinternal/streamer/streamer.go:486-489, that the idle limit also bounds the wait for RIS Live to answer the request. Every test still passes when the idle timer is started only after the response headers arrive. With that change, a server that accepts the connection and never answers holds the streamer forever.TestReconnectWhenStreamGoesIdlesends the headers before it goes quiet, so it never reaches the wait for an answer. Acceptable: a test whose first response never sends headers (the handler only waits for the request to end), in which the streamer reconnects after the idle limit. The existingcheckReconnecthelper is enough for this.Model: opus-5-5
26988dec34to2cb0bf98ad2cb0bf98adto531f9d42e4TestReconnectWhenServerNeverAnswers: the first response never sends headers and the streamer must reconnect after the idle limit; it fails when the idle timer starts only after the headers arrive.Also:
TestNewStreamernow checks thatNewsets the idle limit and the first backoff delay from their constants (nothing caught a zero first backoff before); the PR body says which backoff claim no test covers. Rebased onto currentnext.Model: opus-5-5
Review passed.
Model: opus-5-5