From f2c34eb32eb3bc29f76ea1cbb4264f79a8557fe1 Mon Sep 17 00:00:00 2001 From: Stephen Benjamin Date: Tue, 7 Oct 2025 20:22:08 -0400 Subject: [PATCH 1/2] Fix Docker container hanging in stdio mode by using exec Use exec in docker-entrypoint.sh to replace the shell process with the Python process, making it PID 1. This ensures SIGTERM and SIGINT signals are properly received and handled during shutdown, preventing the container from hanging indefinitely when stopped. Without exec, the shell script remains as PID 1 and doesn't forward signals to the child Python process, causing it to wait forever for stdin to close in stdio mode. Reproducer: ``` $DOCKER run -p 8000:8000 -e DATABASE_URI -access-mode=restricted --transport=sse ``` Without these changes, `^C` does not work and the process is hung forever. After these changes `^C` properly exits. Assisted-by: Cursor AI --- docker-entrypoint.sh | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 434522c..b687cb3 100644 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -94,16 +94,6 @@ echo "${processed_args[@]}" >&2 echo "----------------" >&2 # Execute the command with the processed arguments -"${processed_args[@]}" - -# Capture exit code from the Python process -exit_code=$? - -# If the Python process failed, print additional debug info -if [ $exit_code -ne 0 ]; then - echo "ERROR: Command failed with exit code $exit_code" >&2 - echo "Command was: ${processed_args[@]}" >&2 -fi - -# Return the exit code from the Python process -exit $exit_code +# Use exec to replace the shell with the Python process, making it PID 1 +# This ensures signals (SIGTERM, SIGINT) are properly received +exec "${processed_args[@]}" From f333fce2c8d8388cce8707c2c55dc8f7ad891ac4 Mon Sep 17 00:00:00 2001 From: Stephen Benjamin Date: Tue, 7 Oct 2025 20:28:41 -0400 Subject: [PATCH 2/2] Make Dockerfile buildable and run as non-root I'm not able to build the Dockerfile as the `app` user doesn't exist in the base image. This creates it. It also makes sure the app runs as non-root. --- Dockerfile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Dockerfile b/Dockerfile index 62b0f64..40b744d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,6 +27,8 @@ FROM python:3.12-slim-bookworm # Python executable must be the same, e.g., using `python:3.11-slim-bookworm` # will fail. +RUN groupadd -r app && useradd -r -g app app + COPY --from=builder --chown=app:app /app /app ENV PATH="/app/.venv/bin:$PATH" @@ -50,6 +52,8 @@ RUN apt-get update && apt-get install -y \ COPY docker-entrypoint.sh /app/ RUN chmod +x /app/docker-entrypoint.sh +USER app + # Expose the SSE port EXPOSE 8000