fix(sandbox): handle SIGTERM in docker keep-alive to avoid 30s stop delay - #2885
Merged
Buktal merged 2 commits intoAug 31, 2026
Merged
Conversation
…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 Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
dargoner
pushed a commit
to dargoner/agentscope-java
that referenced
this pull request
Sep 1, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 foregroundsleepthat never observes SIGTERM. In a PID namespace the kernel drops signals to PID 1 that have no installed handler, so whenSandboxManager.release()→sandbox.shutdown()runsdocker stop --time=30(synchronously, on theFlux.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:
trap 'exit 0' TERMregisters a handler on PID 1, so the kernel delivers SIGTERM instead of dropping it.sleep 3600 &+wait $!makesshblock on an interruptiblewait(EINTR). SIGTERM interrupts the wait, the trap runsexit 0, anddocker stopreturns in <1s. A foregroundsleepwould defer the trap until the command returns.Why not
exec sleep infinitysleep infinityis a GNU coreutils extension that BusyBox/Alpinesleeprejects, so it would break container startup on minimal images. Baresleepas PID 1 also has no SIGTERM handler and would still rely on--initto be reliable. The trap approach uses onlysh+ integersleep— the exact same runtime primitives as the old entrypoint — so it stays portable and needs no extradocker runflag.Verification
Measured real
docker stop --time=30withsh -cas PID 1 across images:Old entrypoint consistently hits the 30s grace period then SIGKILL (exit 137); new entrypoint exits cleanly in <0.35s.
Tests
Adds
DockerSandboxRunCommandTestasserting the generateddocker runentrypoint installs the SIGTERM trap, waits on a backgrounded sleep, does not revert to the foreground sleep loop, and avoids the non-portablesleep infinity.