Skip to content

fix(sandbox): handle SIGTERM in docker keep-alive to avoid 30s stop delay - #2885

Merged
Buktal merged 2 commits into
agentscope-ai:mainfrom
larry-zy:fix/docker-sandbox-sigterm-stop-delay
Aug 31, 2026
Merged

fix(sandbox): handle SIGTERM in docker keep-alive to avoid 30s stop delay#2885
Buktal merged 2 commits into
agentscope-ai:mainfrom
larry-zy:fix/docker-sandbox-sigterm-stop-delay

Conversation

@larry-zy

Copy link
Copy Markdown
Contributor

Problem

In Docker sandbox mode, every agent turn incurs a ~30s delay between the agent's last emitted event and the agent.call() Flux terminal signal (onComplete), blocking SSE stream completion.

Root cause: the container keep-alive entrypoint sh -c "while :; do sleep 3600; done" leaves PID 1 (sh) blocked in a foreground sleep that never observes SIGTERM. In a PID namespace the kernel drops signals to PID 1 that have no installed handler, so when SandboxManager.release()sandbox.shutdown() runs docker stop --time=30 (synchronously, on the Flux.using() teardown path), Docker waits the full 30s grace period before escalating to SIGKILL. This happens on every turn regardless of conversation length. Fixes #2884.

Fix

Change the entrypoint to install an explicit SIGTERM trap and wait on a backgrounded sleep:

sh -c "trap 'exit 0' TERM; while :; do sleep 3600 & wait $!; done"
  • trap 'exit 0' TERM registers a handler on PID 1, so the kernel delivers SIGTERM instead of dropping it.
  • sleep 3600 & + wait $! makes sh block on an interruptible wait (EINTR). SIGTERM interrupts the wait, the trap runs exit 0, and docker stop returns in <1s. A foreground sleep would defer the trap until the command returns.

Why not exec sleep infinity

sleep infinity is a GNU coreutils extension that BusyBox/Alpine sleep rejects, so it would break container startup on minimal images. Bare sleep as PID 1 also has no SIGTERM handler and would still rely on --init to be reliable. The trap approach uses only sh + integer sleep — the exact same runtime primitives as the old entrypoint — so it stays portable and needs no extra docker run flag.

Verification

Measured real docker stop --time=30 with sh -c as PID 1 across images:

image shell new (trap+wait) old (foreground)
alpine:latest BusyBox ash 0.33s, exit 0 30.21s, exit 137
ubuntu:22.04 dash 0.14s, exit 0 30.16s, exit 137
busybox:latest BusyBox ash 0.12s, exit 0
debian:bookworm-slim dash 0.18s, exit 0

Old entrypoint consistently hits the 30s grace period then SIGKILL (exit 137); new entrypoint exits cleanly in <0.35s.

Tests

Adds DockerSandboxRunCommandTest asserting the generated docker run entrypoint installs the SIGTERM trap, waits on a backgrounded sleep, does not revert to the foreground sleep loop, and avoids the non-portable sleep infinity.

…elay

The container keep-alive entrypoint ran `sh -c "while :; do sleep 3600;
done"`, where PID 1 (sh) blocks in a foreground `sleep` and never sees
SIGTERM. On `docker stop --time=30` Docker waits the full 30s before
SIGKILL, and since SandboxManager.release() runs shutdown() synchronously
on every turn, each agent call incurs a ~30s delay before the Flux/SSE
stream terminates.

Install a TERM trap and background the sleep with `wait`, so sh exits
promptly on SIGTERM and `docker stop` returns in <1s. This keeps the same
runtime dependencies (sh + integer sleep), so it stays portable across
minimal images where `sleep infinity` is unsupported.

Fixes agentscope-ai#2884
Add unit tests asserting the docker run entrypoint installs a SIGTERM
trap and waits on a backgrounded sleep, does not use the old foreground
sleep loop, and avoids the non-portable `sleep infinity`, so container
teardown cannot silently regress to the ~30s docker stop delay (agentscope-ai#2884).
@codecov

codecov Bot commented Aug 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@Buktal Buktal left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@Buktal
Buktal merged commit 557a816 into agentscope-ai:main Aug 31, 2026
6 checks passed
dargoner pushed a commit to dargoner/agentscope-java that referenced this pull request Sep 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Docker sandbox docker stop waits full 30s due to SIGTERM-ignoring entrypoint

2 participants