Skip to content

webapp wrapper ignores SIGTERM: container is SIGKILLed after the full 10s grace period #5

Description

@dboreham

The webapp wrapper's container ignores SIGTERM, so every stop waits out Docker's full 10s grace period and the process is then SIGKILLed.

Evidence

From a stack Deploy Test CI run — the frontend (webapp wrapper) vs. the backend (node-service wrapper) in the same deployment:

02:41:25.7888  Container ...-frontend-1  Stopping
02:41:35.9030  Container ...-frontend-1  Stopped     <- 10.1s (grace period expired)

02:41:26.4016  Container ...-backend-1   Stopping
02:41:26.4017  Container ...-backend-1   Stopped     <- 0.6s (clean shutdown)

Cause

webapp-base/Containerfile sets CMD ["/scripts/start-serving-app.sh"], so the bash script is PID 1. The last line of that script starts the server as a child process:

http-server $STACK_HTTP_EXTRA_ARGS -p ${STACK_LISTEN_PORT} "${STACK_WEBAPP_FILES_DIR}"

Bash as PID 1 does not forward signals to children, and while waiting on a foreground child it defers the trap until that child exits. So SIGTERM goes to bash and nothing happens; Docker waits 10s, then SIGKILLs the container.

node-service-base/scripts/start-service.sh already does this correctly — it execs in every branch, which is exactly why the backend above stops cleanly. This is a good contrast: the fix is to match it.

Affected

  • webapp-base/scripts/start-serving-app.sh — final http-server invocation
  • nextjs-base/scripts/start-serving-app.sh — final $STACK_BUILD_TOOL start . -- -p ... invocation has the same shape (not directly observed failing, but same pattern)

Not affected: node-service-base (already execs).

Suggested fix

exec the server so it becomes PID 1 and receives signals directly:

exec http-server $STACK_HTTP_EXTRA_ARGS -p ${STACK_LISTEN_PORT} "${STACK_WEBAPP_FILES_DIR}"

Worth checking whether http-server itself handles SIGTERM promptly once it is PID 1; if not, a small init (tini) or an explicit trap would be needed instead.

Impact

Cosmetic in the sense that nothing breaks, but it adds ~10s to every stop/restart of a webapp-wrapped container, which is noticeable in the stack test suites, and it means the server is always killed rather than shut down cleanly — no chance to finish in-flight requests or flush.

Provenance

Noticed while diagnosing unrelated stack Deploy Test failures (the frontend's Vite migration changed the served bundle path). Not investigated further beyond reading the scripts.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions