INITIALIZE · SERVE · DRAIN
Container termination drill: observe an ignored signal
Follow worker lifecycles and the invocations they own. Test readiness, shutdown deadlines and the point at which results commit.
Scroll the worker lanes horizontally. The worker inspector, sums and event trace below provide the same states as text.
Worker and invocation inspector
Committed-output fixture
Completed sums remain visible after a worker exits. This represents an external result store; browser reload does not persist it. Killed invocations have no committed output.
Recent lifecycle decisions
Your experiment
The process ignores the modeled SIGTERM and keeps accepting work until its forced-stop deadline. Enable the handler to withdraw application readiness. Compare killed invocations, then enable a replacement. This explicit router is not Cloud Run’s load balancer or autoscaler; the lesson isolates application shutdown behavior.
Exactly what runs
Requests arrive from t = 1 s through t ≤ 40 s, at the selected interval. Each carries [request number, 1, 2]. The host assigns a free slot and models three equal-duration stages: prepare, model, tool. No AI is called. At completion, actual JavaScript addition computes and commits the sum. Each invocation owns one slot until it completes or its process is killed.
Ready-only routing picks the least-loaded ready worker, with worker ID as a deterministic tie-break. Without that guard it also considers starting and draining workers; those reject the request. There is no admission queue, retry, autoscaler or state transfer. A replacement is a single scheduled boot, not automatic recovery based on load. Startup failure affects only worker 1.
At the signal time, an enabled handler withdraws readiness and drains existing work; an ignored signal leaves the application ready until forced stop. A drained process exits immediately. At a shared timestamp, completions happen before readiness changes, termination and new admission; completion exactly at a shutdown deadline therefore wins in this model. Time is evaluated in 0.1 s steps.
Fixture gate, not a certification
PASS requires zero killed or still-running invocations and a final rejection percentage no greater than the selected allowance. It says nothing about authentication, model quality, real provider SLOs, latency percentiles or production correctness.
Offline, deliberately bounded lifecycle model. It does not execute an ADK Runner, Java process, container, operating-system signal or cloud deployment. Model/tool stages illustrate ownership and timing, not provider computation. The configurable grace period and router are teaching controls, not promises about any cloud runtime. Cloud Run’s documented termination contract and ADK’s invocation event loop must be consulted separately for real implementations. Cloud Run container contract · ADK runtime event loop.
What the platform sends and what this process ignores
When Cloud Run stops a container instance it sends SIGTERM and, per its documented contract, allows ten seconds before SIGKILL. The opening Grace period of ten matches it. In this drill one worker boots in four seconds, requests arrive every two seconds from one second onward, and each invocation needs twenty seconds and holds one of four slots. Handle SIGTERM and stop admission starts cleared, so at thirty seconds the trace records that the handler is disabled and the process keeps accepting work. In a real Java container a common cause is a shell-form entrypoint that never forwards the signal to the JVM.
Follow the request admitted after the signal
At thirty-one seconds request-6 commits and request-16 is admitted in the same instant, one second after SIGTERM. At forty seconds the forced stop kills request-13, request-14, request-15 and request-16. The run ends with 20 arrivals, 8 admitted, 12 rejected, 4 completed and 4 killed, and the fixture gate fails at 60.0 percent rejected. Raise Grace period to nineteen: request-13, request-14 and request-15 commit at 45, 47 and 49 seconds, but request-16 is still killed because it needs until fifty-one. Twenty, the maximum, does the same. While the signal is ignored, no reachable grace protects work started after it.
Handle the signal, then size the grace period
Enable Handle SIGTERM and stop admission and restore grace ten. request-16 is now rejected with no eligible worker, yet request-13, request-14 and request-15 are still killed because twenty-second work cannot finish in ten. Grace nineteen gives zero killed and an exit at forty-nine seconds; eighteen kills one, because request-15 completes exactly at the 49-second deadline and completions win ties here. Alternatively set Invocation duration to eight with grace ten: thirteen complete, none are killed and the process exits at thirty-seven. Clear the handler with the same duration and request-17 to request-20, all admitted after the signal, are killed.
The remaining inputs
With duration eight and the handler on, Initial workers two gives eighteen completed, zero killed and a PASS at ten percent rejected; ignore the signal and request-17 and request-19 are killed on worker-1. Invocation slots per worker, Startup duration and Request interval change who is admitted. From the opening settings (reload the page), Signal worker 1 at forty kills only request-16. Fail initialization of worker 1 rejects all twenty arrivals. Boot one replacement at signal time readies a worker at thirty-four seconds that completes three more invocations, but four are still killed. Route only to ready workers changes only rejection reasons by default. Fixture rejection allowance decides only zero-kill runs: handler on, grace twenty gives 65.0 percent, FAIL at 25, PASS at 65. Common baseline settings loads a two-worker reference that passes.
Inspection and limits
Play, Pause, Step 1 second, Restart, Speed and Simulation time replay sixty seconds; edits recompute and rewind. Every opening event falls between zero and forty seconds. Choose worker or click its lane shows one worker as JSON. The router is a teaching device, not the Cloud Run front end or autoscaler; there are no HTTP connections, JVM shutdown hooks, retries or real signals.