From d1f912baae19fd32ae1e332cad91ab2605f0a82a Mon Sep 17 00:00:00 2001 From: sneak Date: Mon, 28 Sep 2026 18:11:11 +0000 Subject: [PATCH 1/2] Let the daemon receive docker stop's signal itself (closes #33) entrypoint.sh now switches to the routewatch user with setpriv instead of runuser. setpriv replaces itself with the daemon, so the daemon gets the stop signal directly and has its full 60 seconds to shut down; runuser stayed in between and killed the daemon 2 seconds after passing the signal on. setpriv keeps the environment, so GOMEMLIMIT, MALLOC_ARENA_MAX and XDG_DATA_HOME still reach the daemon, and the state directory stays /var/lib/berlin.sneak.app.routewatch. Model: opus-5-5 --- Dockerfile | 4 ++-- TODO.md | 4 ++++ entrypoint.sh | 5 ++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 83d9ed0..cedd1c9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -79,8 +79,8 @@ RUN chown -R routewatch:routewatch /app ENV XDG_DATA_HOME=/var/lib # Cap the Go heap at 1.5 GiB so the runtime collects harder before the -# container's memory limit is reached. runuser preserves this the way it does -# XDG_DATA_HOME above. +# container's memory limit is reached. setpriv in the entrypoint preserves this +# the way it does XDG_DATA_HOME above. ENV GOMEMLIMIT=1536MiB # Cap glibc's malloc arenas. The SQLite C library allocates and frees millions diff --git a/TODO.md b/TODO.md index fea8ac6..fc94648 100644 --- a/TODO.md +++ b/TODO.md @@ -23,6 +23,10 @@ runs make check on main. # Completed Steps +- 2026-09-28: `docker stop` no longer kills the daemon 2 seconds after the + stop signal: the entrypoint switches to the `routewatch` user with + `setpriv` instead of `runuser`, so the daemon receives the signal itself + and gets its full 60 seconds to shut down (closes #33) - 2026-09-28: ready to run under upaas: a set but invalid `PORT`, `XDG_DATA_HOME` or `MALLOC_ARENA_MAX` stops the start, the health check follows `PORT`, README "Running under upaas" section (closes diff --git a/entrypoint.sh b/entrypoint.sh index 3f0d092..7679fad 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -10,4 +10,7 @@ cd /var/lib/berlin.sneak.app.routewatch chown -R routewatch:routewatch . chmod 700 . -exec runuser -u routewatch -- /app/routewatch +# setpriv replaces itself with the daemon, so the daemon receives the stop +# signal directly. runuser would stay in between and kill the daemon 2 seconds +# after passing the signal on. +exec setpriv --reuid=routewatch --regid=routewatch --init-groups -- /app/routewatch -- 2.54.0 From 3310376e2a823b5be644109cec2ee016f9bc3287 Mon Sep 17 00:00:00 2001 From: sneak Date: Mon, 28 Sep 2026 18:43:17 +0000 Subject: [PATCH 2/2] Correct the stop-time wording in TODO.md The daemon is no longer killed 2 seconds after the stop signal, so it gets the whole wait docker stop allows, up to its own 60-second limit; it does not always get 60 seconds. Model: opus-5-5 --- TODO.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/TODO.md b/TODO.md index fc94648..f74ae68 100644 --- a/TODO.md +++ b/TODO.md @@ -26,7 +26,8 @@ runs make check on main. - 2026-09-28: `docker stop` no longer kills the daemon 2 seconds after the stop signal: the entrypoint switches to the `routewatch` user with `setpriv` instead of `runuser`, so the daemon receives the signal itself - and gets its full 60 seconds to shut down (closes #33) + and gets the whole wait `docker stop` allows, up to its own 60-second + limit (closes #33) - 2026-09-28: ready to run under upaas: a set but invalid `PORT`, `XDG_DATA_HOME` or `MALLOC_ARENA_MAX` stops the start, the health check follows `PORT`, README "Running under upaas" section (closes -- 2.54.0