docker stop kills the daemon 2 seconds after the stop signal #33

Closed
opened 2026-09-28 19:24:03 +02:00 by clawbot · 2 comments
Collaborator

Found while checking #32 for #31. Every docker stop ends with the daemon killed: entrypoint.sh starts it through runuser, which on the stop signal passes it on, waits 2 seconds, then kills the daemon outright and prints ...killed.; the container exits 143. The daemon allows itself 60 seconds to shut down (shutdownTimeout, internal/routewatch/cli.go), so any shutdown longer than 2 seconds is cut off. upaas stops the container on every redeploy.

Definition of done

  • entrypoint.sh still starts as root and takes ownership of the state directory, then replaces itself with the daemon running as the routewatch user (UID 1000), so the daemon itself receives the stop signal. setpriv from util-linux, already in the runtime image, does this; runuser goes.
  • With the image built by make docker: docker stop -t 70 lets the shutdown finish, the log shows it completing, and nothing is killed; the daemon runs as UID 1000; a fresh root-owned state directory still works.
  • make check stays green (in the Docker build).

Model: opus-5-5

Found while checking https://git.eeqj.de/sneak/routewatch/pulls/32 for https://git.eeqj.de/sneak/routewatch/issues/31. Every `docker stop` ends with the daemon killed: `entrypoint.sh` starts it through `runuser`, which on the stop signal passes it on, waits 2 seconds, then kills the daemon outright and prints `...killed.`; the container exits 143. The daemon allows itself 60 seconds to shut down (`shutdownTimeout`, `internal/routewatch/cli.go`), so any shutdown longer than 2 seconds is cut off. upaas stops the container on every redeploy. ## Definition of done - `entrypoint.sh` still starts as root and takes ownership of the state directory, then replaces itself with the daemon running as the `routewatch` user (UID 1000), so the daemon itself receives the stop signal. `setpriv` from util-linux, already in the runtime image, does this; `runuser` goes. - With the image built by `make docker`: `docker stop -t 70` lets the shutdown finish, the log shows it completing, and nothing is killed; the daemon runs as UID 1000; a fresh root-owned state directory still works. - `make check` stays green (in the Docker build). Model: opus-5-5
clawbot self-assigned this 2026-09-28 19:24:03 +02:00
Author
Collaborator

Implementer's notes, on top of the definition of done above:

  • setpriv keeps the environment as it is, so GOMEMLIMIT, MALLOC_ARENA_MAX and XDG_DATA_HOME still reach the daemon; the Dockerfile comment above ENV GOMEMLIMIT that names runuser changes with it.
  • Unlike runuser, setpriv leaves HOME as root's. The daemon reads HOME only when XDG_DATA_HOME is unset, which the image never is; confirm the state directory is still /var/lib/berlin.sneak.app.routewatch.
  • The check runs as root before the user switch, so the MALLOC_ARENA_MAX refusal from #31 stays where it is.

Model: opus-5-5

Implementer's notes, on top of the definition of done above: - `setpriv` keeps the environment as it is, so `GOMEMLIMIT`, `MALLOC_ARENA_MAX` and `XDG_DATA_HOME` still reach the daemon; the `Dockerfile` comment above `ENV GOMEMLIMIT` that names `runuser` changes with it. - Unlike `runuser`, `setpriv` leaves `HOME` as root's. The daemon reads `HOME` only when `XDG_DATA_HOME` is unset, which the image never is; confirm the state directory is still `/var/lib/berlin.sneak.app.routewatch`. - The check runs as root before the user switch, so the `MALLOC_ARENA_MAX` refusal from https://git.eeqj.de/sneak/routewatch/issues/31 stays where it is. Model: opus-5-5
Author
Collaborator

PR: #35

Model: opus-5-5

PR: https://git.eeqj.de/sneak/routewatch/pulls/35 Model: opus-5-5
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/routewatch#33