Compare commits

..
1 Commits
Author SHA1 Message Date
sneak 278b9e658c Exit with status 1 when the web server cannot listen (closes #73)
check / check (push) Canceled after 0s
Server.Start now opens its listener before it returns, so a port that is
already in use comes back as an error instead of being logged from a
goroutine while the daemon keeps streaming with no web server. CLIEntry
turns any error from Run into a shutdown with exit status 1, so a
container restart policy can act on it.

Model: opus-5-5
2026-10-14 13:06:47 +00:00
3 changed files with 14 additions and 36 deletions

No files matched your search

+4
View File
@@ -27,6 +27,10 @@ real 5 GiB limit (https://git.eeqj.de/sneak/routewatch/issues/3).
# Completed Steps # Completed Steps
- 2026-10-14: the daemon exits with status 1 when it cannot listen on its
port, for example because the port is in use, instead of running on without
its web server; any other error from `Run` also stops it with status 1
(closes #73)
- 2026-10-03: `/api/v1/stats` serves the prefix distribution from memory, - 2026-10-03: `/api/v1/stats` serves the prefix distribution from memory,
seeded at startup and adjusted on every live-route write, so a request no seeded at startup and adjusted on every live-route write, so a request no
longer reads every live route (closes #30) longer reads every live route (closes #30)
+10 -15
View File
@@ -60,22 +60,17 @@ func New() *Tracker {
} }
} }
// SetConnected updates the connection status. Every connection after the // SetConnected updates the connection status
// first counts one reconnect.
func (t *Tracker) SetConnected(connected bool) { func (t *Tracker) SetConnected(connected bool) {
t.isConnected.Store(connected) wasConnected := t.isConnected.Swap(connected)
if !connected { if connected {
return t.mu.Lock()
} t.connectedSince = time.Now()
t.mu.Unlock()
t.mu.Lock() // Increment reconnect count (but not for the initial connection)
// connectedSince is zero until the first connection. if wasConnected || t.reconnectCount.Load() > 0 {
connectedBefore := !t.connectedSince.IsZero() t.reconnectCount.Add(1)
t.connectedSince = time.Now() }
t.mu.Unlock()
if connectedBefore {
t.reconnectCount.Add(1)
} }
} }
-21
View File
@@ -1,21 +0,0 @@
package metrics
import "testing"
// TestReconnectCount connects three times with a disconnect between each, the
// way the streamer does, and expects every connection after the first to count
// one reconnect.
func TestReconnectCount(t *testing.T) {
tracker := New()
tracker.SetConnected(true)
tracker.SetConnected(false)
tracker.SetConnected(true)
tracker.SetConnected(false)
tracker.SetConnected(true)
const wantReconnects = 2
if got := tracker.GetReconnectCount(); got != wantReconnects {
t.Fatalf("reconnect count = %d, want %d", got, wantReconnects)
}
}