From 78dfc0e2b840d4bb660971e15d233cee5ba89848 Mon Sep 17 00:00:00 2001 From: alexbelgium Date: Tue, 13 Oct 2026 22:22:10 +0200 Subject: [PATCH] fix(templates): stop the service's whole process group, and wait for it to empty A run file that does not exec its daemon only had its wrapper shell signalled: portainer_agent's own run file, and LinuxServer's svc-transmission in base images we cannot edit. Each loop subshell now runs with job control (set -m), so every service is its own process group; the stop is sent to the group and PID 1 waits until the group is empty, so the daemon drains instead of being SIGKILLed when PID 1 exits. Docker's stop timeout still bounds it. Revision drafted by Codex (gpt-5.6-sol); the group-drain wait was added after a PID-1 test showed the daemon got TERM but was killed mid-drain. Co-Authored-By: Claude Opus 5.5 --- .templates/ha_entrypoint.sh | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.templates/ha_entrypoint.sh b/.templates/ha_entrypoint.sh index 96737d07c5..8502d7fbc5 100755 --- a/.templates/ha_entrypoint.sh +++ b/.templates/ha_entrypoint.sh @@ -438,20 +438,23 @@ if $PID1; then restart_count=0 max_restarts=5 # terminate() signals only PID 1's direct children, which are these loop subshells. - # Run each service in the background and forward the stop to it, so it shuts down - # cleanly instead of being SIGKILLed when PID 1 exits, and is not restarted after. + # Give each background job its own process group and forward the stop to the whole + # group, so wrappers and their daemons can shut down before PID 1 exits. + set -m stopping=false service_pid= - trap 'stopping=true; [ -z "$service_pid" ] || kill -TERM "$service_pid" 2>/dev/null || true' TERM INT + trap 'stopping=true; [ -z "$service_pid" ] || kill -TERM -- "-$service_pid" 2>/dev/null || true' TERM INT wait_for_service() { local pid="$service_pid" if $stopping; then - kill -TERM "$pid" 2>/dev/null || true + kill -TERM -- "-$pid" 2>/dev/null || true fi _svc_rc=0 - wait "$pid" || _svc_rc=$? + wait "$pid" 2>/dev/null || _svc_rc=$? if $stopping; then wait "$pid" 2>/dev/null || true + # A run file that does not exec its daemon dies first; wait for the whole group + while kill -0 -- "-$pid" 2>/dev/null; do sleep 0.2; done service_pid= return 1 fi