The server lifecycle example in prompts/GO_HTTP_SERVER_CONVENTIONS.md has three defects that a repo copying it inherits. pixa had all three and fixed them in sneak/pixa#169 (for sneak/pixa#86).
serve() computes an exit code, but nothing passes it to os.Exit: the process exits 0 even when it stopped because of an error, so a supervisor sees a crash as a clean stop.
serve() installs its own SIGINT/SIGTERM handler while the fx app's Run() installs another. Both fire on one signal and race to shut down.
When Sentry cannot start, the example calls os.Exit(1) from a goroutine, so no fx stop hook runs (the database and work in progress are abandoned).
The shape pixa now uses: main calls Run() on the fx app and lets fx own signals; a listen error asks fx to shut down with exit code 1 (fx.Shutdowner with fx.ExitCode(1)); the server's stop hook shuts the HTTP server down within its time limit and fails if work is unfinished; a Sentry start failure is returned from the start hook, so fx reports it and exits 1. fx's Run() exits with the code the shutdown carried.
Done when the example no longer has these three defects, and the conventions describe how exit codes and signals are owned.
Model: opus-5-5
The server lifecycle example in `prompts/GO_HTTP_SERVER_CONVENTIONS.md` has three defects that a repo copying it inherits. pixa had all three and fixed them in https://git.eeqj.de/sneak/pixa/pulls/169 (for https://git.eeqj.de/sneak/pixa/issues/86).
1. `serve()` computes an exit code, but nothing passes it to `os.Exit`: the process exits 0 even when it stopped because of an error, so a supervisor sees a crash as a clean stop.
2. `serve()` installs its own SIGINT/SIGTERM handler while the fx app's `Run()` installs another. Both fire on one signal and race to shut down.
3. When Sentry cannot start, the example calls `os.Exit(1)` from a goroutine, so no fx stop hook runs (the database and work in progress are abandoned).
The shape pixa now uses: `main` calls `Run()` on the fx app and lets fx own signals; a listen error asks fx to shut down with exit code 1 (`fx.Shutdowner` with `fx.ExitCode(1)`); the server's stop hook shuts the HTTP server down within its time limit and fails if work is unfinished; a Sentry start failure is returned from the start hook, so fx reports it and exits 1. fx's `Run()` exits with the code the shutdown carried.
Done when the example no longer has these three defects, and the conventions describe how exit codes and signals are owned.
Model: opus-5-5
Plan. Rewrite the lifecycle example in prompts/GO_HTTP_SERVER_CONVENTIONS.md to the shape above: main calls Run() on the fx app and fx owns signals; a listen error shuts fx down with fx.ExitCode(1) through fx.Shutdowner; the stop hook shuts the HTTP server down within its time limit; a Sentry start failure is returned from the start hook. Drop the example's own signal.Notify, its exitCode field and the os.Exit in enableSentry(). Fix every other place in the document, and in prompts/CODE_STYLEGUIDE_GO.md if it restates the lifecycle, and add one short paragraph saying who owns signals and the exit code.
Done when a throwaway module built from the example as written exits 0 on SIGTERM, exits 1 after its stop hooks run on a listen error (port taken) and on a Sentry start failure (invalid DSN), and make check passes.
Model: opus-5-5
Plan. Rewrite the lifecycle example in `prompts/GO_HTTP_SERVER_CONVENTIONS.md` to the shape above: `main` calls `Run()` on the fx app and fx owns signals; a listen error shuts fx down with `fx.ExitCode(1)` through `fx.Shutdowner`; the stop hook shuts the HTTP server down within its time limit; a Sentry start failure is returned from the start hook. Drop the example's own `signal.Notify`, its `exitCode` field and the `os.Exit` in `enableSentry()`. Fix every other place in the document, and in `prompts/CODE_STYLEGUIDE_GO.md` if it restates the lifecycle, and add one short paragraph saying who owns signals and the exit code.
Done when a throwaway module built from the example as written exits 0 on SIGTERM, exits 1 after its stop hooks run on a listen error (port taken) and on a Sentry start failure (invalid DSN), and `make check` passes.
Model: opus-5-5
clawbot
self-assigned this 2026-10-04 08:49:37 +02:00
Done in #94: the server example now lets fx own SIGINT, SIGTERM and the exit code, a listen error shuts fx down with exit code 1, a Sentry start failure is returned from the start hook, and the stop hook fails when requests outlive its 5 seconds. A new paragraph says who owns signals and the exit code.
Model: opus-5-5
Done in https://git.eeqj.de/sneak/prompts/pulls/94: the server example now lets fx own SIGINT, SIGTERM and the exit code, a listen error shuts fx down with exit code 1, a Sentry start failure is returned from the start hook, and the stop hook fails when requests outlive its 5 seconds. A new paragraph says who owns signals and the exit code.
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.
The server lifecycle example in
prompts/GO_HTTP_SERVER_CONVENTIONS.mdhas three defects that a repo copying it inherits. pixa had all three and fixed them in sneak/pixa#169 (for sneak/pixa#86).serve()computes an exit code, but nothing passes it toos.Exit: the process exits 0 even when it stopped because of an error, so a supervisor sees a crash as a clean stop.serve()installs its own SIGINT/SIGTERM handler while the fx app'sRun()installs another. Both fire on one signal and race to shut down.os.Exit(1)from a goroutine, so no fx stop hook runs (the database and work in progress are abandoned).The shape pixa now uses:
maincallsRun()on the fx app and lets fx own signals; a listen error asks fx to shut down with exit code 1 (fx.Shutdownerwithfx.ExitCode(1)); the server's stop hook shuts the HTTP server down within its time limit and fails if work is unfinished; a Sentry start failure is returned from the start hook, so fx reports it and exits 1. fx'sRun()exits with the code the shutdown carried.Done when the example no longer has these three defects, and the conventions describe how exit codes and signals are owned.
Model: opus-5-5
Plan. Rewrite the lifecycle example in
prompts/GO_HTTP_SERVER_CONVENTIONS.mdto the shape above:maincallsRun()on the fx app and fx owns signals; a listen error shuts fx down withfx.ExitCode(1)throughfx.Shutdowner; the stop hook shuts the HTTP server down within its time limit; a Sentry start failure is returned from the start hook. Drop the example's ownsignal.Notify, itsexitCodefield and theos.ExitinenableSentry(). Fix every other place in the document, and inprompts/CODE_STYLEGUIDE_GO.mdif it restates the lifecycle, and add one short paragraph saying who owns signals and the exit code.Done when a throwaway module built from the example as written exits 0 on SIGTERM, exits 1 after its stop hooks run on a listen error (port taken) and on a Sentry start failure (invalid DSN), and
make checkpasses.Model: opus-5-5
Done in #94: the server example now lets fx own SIGINT, SIGTERM and the exit code, a listen error shuts fx down with exit code 1, a Sentry start failure is returned from the start hook, and the stop hook fails when requests outlive its 5 seconds. A new paragraph says who owns signals and the exit code.
Model: opus-5-5