Skip to content

serve: don't drop the server start error on the way out#889

Open
c-tonneslan wants to merge 1 commit into
charmbracelet:mainfrom
c-tonneslan:fix/serve-surface-bind-error
Open

serve: don't drop the server start error on the way out#889
c-tonneslan wants to merge 1 commit into
charmbracelet:mainfrom
c-tonneslan:fix/serve-surface-bind-error

Conversation

@c-tonneslan
Copy link
Copy Markdown

Closes #645.

The run loop selects between `lch` (the server's exit error from `s.Start`) and `done` (signal or close). When `s.Start` fails early (e.g. `bind: permission denied` on `:22` as an unprivileged user, which is the repro in #645), the goroutine writes to `lch` and then `doneOnce()` closes `done`. Both channels are then ready at the same time, and the select picks one at random — about half the time it takes `done` first, falls through to the shutdown path, and the bind error never makes it back to the caller. The user sees soft "start" successfully, but no listener on the configured port and nothing in the logs.

When the `done` case fires with a nil `sig` (which means `done` was closed by `doneOnce`, not raised by a real signal), drain `lch` and return whatever error the server reported. Real signal-driven shutdowns (non-nil `sig`) still take the graceful path.

@aymanbagabas — you pointed at this spot in the issue thread, hopefully this matches what you had in mind.

The run loop selects between two channels: lch (the server's exit
error from s.Start) and done (signal or close). When s.Start fails
early (e.g. bind: permission denied on :22 under an unprivileged
user, see charmbracelet#645), the goroutine writes to lch and then doneOnce()
closes done. Both are then ready at the same time, and Go picks one
at random. About half the time the select takes done first, falls
through to the shutdown path, and the bind error never gets surfaced
to the user, who just sees soft "start" successfully and then no
listener on the configured port.

When the done case fires with a nil sig (i.e. done was closed by
doneOnce, not by a real signal), drain lch and return whatever error
the server reported. Real signals (SIGINT/TERM with a non-nil sig)
still take the graceful path.

Closes charmbracelet#645

Signed-off-by: Charlie Tonneslan <cst0520@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

No error or warnings when soft cannot bind to privileged ports (Debian 12)

1 participant