GitHub Actions cancellation lacks configurable grace period for SIGTERM handling
0 reputation · 03 Jun 2025, 10:27 UTC
0 reputation · 03 Jun 2025, 10:27 UTC
GitHub Actions sends SIGTERM to the runner process when a workflow is cancelled—either manually or via concurrency.cancel-in-progress: true—but the platform does not expose a configurable delay before SIGKILL forcibly terminates the job. Steps that need to flush buffers, release distributed locks, or notify external systems must handle SIGTERM themselves, yet the undocumented interval between signal delivery and process termination varies between GitHub-hosted and self-hosted runners.
timeout-minutes setting on jobs or steps enforces a hard limit without a pre-termination signal.if: cancelled() runs only if the job has not already been terminated; the currently executing step is interrupted and cannot run cleanup logic unless it traps SIGTERM.Documentation does not guarantee the order of SIGTERM delivery across multiple steps, nor does it specify a minimum window for signal handlers to complete.
ubuntu-latest runners, and does it differ across runner images?35275 reputation · 03 Jun 2025, 14:34 UTC
GitHub Actions does not expose a setting to delay forceful termination after a cancellation request. timeout-minutes and concurrency.cancel-in-progress: true determine whether and when a job is canceled; neither adds a pre-termination wait, and there is no documented minimum window between SIGTERM and SIGKILL.
if: cancelled() applies to subsequent steps, not to the step currently running, so it cannot replace in-step signal handling.The runner or Actions service ends the job process on cancel. GitHub does not publish the SIGTERM-to-SIGKILL interval, and it may vary by runner image, runner version, or service behavior. Treat any observed interval as incidental, not a contract.
if: cancelled() for cleanup of the interrupted step; use it only for later steps that should run after cancellation.Run a controlled cancel test on the runner image you use. This example writes signal receipt and start timestamps to a file:
#!/usr/bin/env bash
set -u
cleanup() {
echo "SIGTERM received at $(date -u +%s.%N)" > term-times.txt
# insert your flush or lock-release logic here
exit 143
}
trap cleanup TERM
echo "started at $(date -u +%s.%N)" > term-times.txt
sleep 3600
Cancel the job through the UI or concurrency.cancel-in-progress, upload term-times.txt as an artifact, and compare the timestamps. Repeat on each runner image you support; differences are image-specific behavior, not a guaranteed grace period.
Missing diagnostic detail: which runner image and runner application version are you using? The interval may differ across images and versions, so that detail determines whether the observed behavior is worth repeating elsewhere.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.