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
+4
View File
@@ -27,6 +27,10 @@ real 5 GiB limit (https://git.eeqj.de/sneak/routewatch/issues/3).
# 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,
seeded at startup and adjusted on every live-route write, so a request no
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
// first counts one reconnect.
// SetConnected updates the connection status
func (t *Tracker) SetConnected(connected bool) {
t.isConnected.Store(connected)
if !connected {
return
}
t.mu.Lock()
// connectedSince is zero until the first connection.
connectedBefore := !t.connectedSince.IsZero()
t.connectedSince = time.Now()
t.mu.Unlock()
if connectedBefore {
t.reconnectCount.Add(1)
wasConnected := t.isConnected.Swap(connected)
if connected {
t.mu.Lock()
t.connectedSince = time.Now()
t.mu.Unlock()
// Increment reconnect count (but not for the initial connection)
if wasConnected || t.reconnectCount.Load() > 0 {
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)
}
}