server: a port that cannot be bound stops startup (closes #266) #275

Merged
clawbot merged 1 commits from fix/266-listen-failure-exits into next 2026-10-13 18:00:01 +02:00
Collaborator

Fixes #266.

The server's start hook now binds the listen port itself and only then serves on it in a goroutine. A port that cannot be bound, such as one already in use or a privileged port without root, comes back from the start hook as an error, so fx stops startup and exits 1, logging for example starting http server: listen tcp :8080: bind: address already in use. Before, the bind happened inside the goroutine and its error was only logged while the watcher kept running without the dashboard, API or health check.

Run now takes the start hook's context and returns once the port is bound instead of blocking. The http.Server is built before the goroutine starts, so Shutdown no longer reads a field another goroutine may still be writing.

TestPortInUseStopsStartup holds a port and checks that starting the server on it fails with an error naming it. TestRunWiresSocketTimeouts now expects Run to return the bind error for port -1.

The README's PORT row says a port that cannot be bound stops startup.

Deviation: net.ListenConfig.Listen instead of the issue's net.Listen, which the repo's linter rejects for taking no context.
Unverified: the exit status 1 comes from fx's App.Run on a failed start (fx v1.24.0); no test runs the binary.

Model: opus-5-5

Fixes https://git.eeqj.de/sneak/dnswatcher/issues/266. The server's start hook now binds the listen port itself and only then serves on it in a goroutine. A port that cannot be bound, such as one already in use or a privileged port without root, comes back from the start hook as an error, so fx stops startup and exits 1, logging for example `starting http server: listen tcp :8080: bind: address already in use`. Before, the bind happened inside the goroutine and its error was only logged while the watcher kept running without the dashboard, API or health check. `Run` now takes the start hook's context and returns once the port is bound instead of blocking. The `http.Server` is built before the goroutine starts, so `Shutdown` no longer reads a field another goroutine may still be writing. `TestPortInUseStopsStartup` holds a port and checks that starting the server on it fails with an error naming it. `TestRunWiresSocketTimeouts` now expects `Run` to return the bind error for port -1. The README's `PORT` row says a port that cannot be bound stops startup. Deviation: `net.ListenConfig.Listen` instead of the issue's `net.Listen`, which the repo's linter rejects for taking no context. Unverified: the exit status 1 comes from fx's `App.Run` on a failed start (fx v1.24.0); no test runs the binary. Model: opus-5-5
clawbot added the needs-review label 2026-10-13 14:05:32 +02:00
clawbot self-assigned this 2026-10-13 14:05:32 +02:00
Author
Collaborator

Review: FAIL

  • Needs rebase onto current next: TODO.md no longer applies cleanly, because the Completed Steps entry for #269 now sits on next at the line this PR adds its entry to. Acceptable: the one commit rebased onto current next, with both Completed Steps entries kept.

Model: opus-5-5

Review: FAIL - Needs rebase onto current `next`: `TODO.md` no longer applies cleanly, because the Completed Steps entry for https://git.eeqj.de/sneak/dnswatcher/issues/269 now sits on `next` at the line this PR adds its entry to. Acceptable: the one commit rebased onto current `next`, with both Completed Steps entries kept. Model: opus-5-5
clawbot added needs-rebase and removed needs-review labels 2026-10-13 15:38:20 +02:00
clawbot added 1 commit 2026-10-13 16:30:51 +02:00
The start hook now binds the listen port itself and serves on it in a
goroutine. A bind failure, such as a port already in use or a
privileged port without root, is returned to fx, which stops startup
and exits 1 with an error like "starting http server: listen tcp
:8080: bind: address already in use". Before, the bind happened inside
the goroutine and its error was only logged while the watcher kept
running without the dashboard, API or health check.

The http.Server is now built before that goroutine starts, so Shutdown
no longer reads a field another goroutine may still be writing.

TestPortInUseStopsStartup holds a port and checks that starting the
server on it fails with an error naming it.

Model: opus-5-5
clawbot force-pushed fix/266-listen-failure-exits from b9c6d43722 to af4fe4d1b7 2026-10-13 16:30:51 +02:00 Compare
Author
Collaborator

Rebase onto current next: the one commit now sits on top of #269, with both Completed Steps entries kept in TODO.md, this one first.

Model: opus-5-5

Rebase onto current `next`: the one commit now sits on top of https://git.eeqj.de/sneak/dnswatcher/issues/269, with both Completed Steps entries kept in `TODO.md`, this one first. Model: opus-5-5
clawbot added needs-review and removed needs-rebase labels 2026-10-13 16:30:57 +02:00
Author
Collaborator

Review: PASS

Model: opus-5-5

Review: PASS Model: opus-5-5
clawbot removed the needs-review label 2026-10-13 17:48:43 +02:00
clawbot merged commit 2ae6110414 into next 2026-10-13 18:00:01 +02:00
clawbot deleted branch fix/266-listen-failure-exits 2026-10-13 18:00:01 +02:00
Sign in to join this conversation.