server: no SIGTERM handler, so every deploy burns 10s and drops in-flight requests #107
Etiketter
Inga etiketter
area/backups
area/ci
area/control-panel
area/identity
area/infra
area/observability
area/payments
area/security
area/storage
area/web
blocked
needs-info
needs-triage
ready-for-implementation
type
bug
type
chore
type
docs
type
epic
type
feature
type
task
wontfix
Ingen milstolpe
Inget projekt
Inga tilldelade
1 deltagare
Notiser
Förfallodatum
Inget förfallodatum satt.
Beroenden
Inga beroenden satta
Referens
bitborg/bitborg-web#107
Läser in…
Hänvisa till i nytt ärende
Ingen beskrivning angiven.
Ta bort grenen "%!s()"
Borttagning av en gren är permanent. Även om den borttagna grenen kan fortsätta existera en kort tid innan den faktiskt tas bort, kan det INTE ångras i de flesta fall. Vill du fortsätta?
The server does not handle
SIGTERM, so every deploy spends a fixed 10 seconds waiting for agraceful stop that never happens, then gets
SIGKILLed. In-flight requests are dropped abruptlyrather than drained.
Evidence
From the services host journal, on the 2026-07-29 22:27 UTC deploy:
Every deploy shows the same 10.1 s gap. It is the second-largest component of deploy downtime.
Why it happens
Containerfileends with:The
execcorrectly hands PID 1 to the server, so the process does receiveSIGTERM— thecomment in the Containerfile is right that this is what makes signal handling possible. But the Astro
node adapter's standalone server installs no
SIGTERMhandler, and Node's default action for a signalwith no handler and no default disposition is to do nothing. So the process sits there until Podman's
10 s
StopTimeoutexpires.This is a stop-path defect, not a startup one: nothing is broken on the way up.
Consequences
AutoUpdate=registry), sothis is a recurring, entirely avoidable cost.
dropped connection. The severity is currently masked by a much larger infra-side delay, but it is
independent of it.
being able to stop draining-first; an instance that must be
SIGKILLed cannot participate in one.Fix
Install a signal handler that stops accepting new connections, closes idle ones, and exits once
in-flight requests finish or a deadline passes:
SIGTERMandSIGINT.server.close()to stop accepting, plusserver.closeIdleConnections()so keep-alive sockets donot hold the process open for the full timeout.
StopTimeout(default 10 s) — e.g. 5 s — thenprocess.exit(0),so a stuck request cannot reintroduce the
SIGKILLpath.The Astro node adapter in standalone mode does not expose its
http.Serverdirectly, so the handlerneeds a small wrapper entry point around
dist/server/entry.mjs, or the adapter's middleware modewith our own server. Worth checking which the current adapter version supports before choosing.
Acceptance
SIGTERMto the running container exits cleanly in well under 10 s.resorting to SIGKILLwarning in the journal on a deploy.Context
Found while measuring the deploy phase breakdown after the 502s in bitborg-infra #249 / #250. The
dominant cost there is a separate infra-side regression filed against bitborg-infra; this 10 s is the
app's own share and is fixable independently of it.