How to Run a Long Job With a Heartbeat in GitHub Actions
A long, quiet step looks hung and risks the no-output timeout; a heartbeat proves it is alive.
Start a background loop that prints a timestamp every minute, run the long task, then stop the heartbeat in a cleanup.
Steps
- Start a background loop that echoes progress on an interval.
- Capture its PID so you can stop it later.
- Run the long-running task in the foreground.
- Kill the heartbeat in an
always()cleanup step.
Workflow
.github/workflows/long.yml
jobs:
long:
runs-on: ubuntu-latest
timeout-minutes: 120
steps:
- uses: actions/checkout@v4
- name: Run with heartbeat
run: |
( while true; do echo "heartbeat $(date -u +%T)"; sleep 60; done ) &
HB=$!
./long-task.sh
kill $HBGotchas
- Set a generous
timeout-minutesso the job is not cut off mid-task. - Use
set -o pipefailso a failing long task is not masked by the heartbeat. - Latchkey runs long jobs on cheaper runners that self-heal, so a transient infra blip does not waste hours of work.
Related guides
How to Run a Job on a Self-Hosted Label in GitHub ActionsTarget a self-hosted runner by label in GitHub Actions using a runs-on array, so a job lands only on runners…
How to Retry Only the Failed Matrix Legs in GitHub ActionsRe-run only the failed legs of a GitHub Actions matrix using fail-fast false and a per-step retry action, so…