Description
A single act_runner (v2.0.0, capacity: 1) periodically stops picking up work
without any error and without exiting. The server considers the runner healthy and
assigns jobs to it — the job flips to in_progress and its task row is created —
but the runner never logs receiving that task, so every step stays queued forever
until the runner process is restarted.
This is not the "job stays waiting / never gets assigned" behaviour described in
#33492. Here the job is assigned; it is the runner that never acts on it.
Environment
|
|
| Gitea server |
1.26.4 |
| act_runner |
v2.0.0 |
| Runner count |
1 runner with the relevant label (a second runner exists but its labels do not overlap) |
runner.capacity |
1 |
log.level |
debug |
| OS |
NixOS (runner runs as a systemd service on the same LAN as the server) |
⚠️ Note this is explicitly the configuration that #33492 states is not affected
("single runner setups does not seem to be affected"). We reproduce it with one
runner and no parallelism.
Observed behaviour
Normal cycle (from debug logs)
17:44:19 level=info msg="runner: <name>, with version: v2.0.0, with labels: [<label>], declare successfully" daemon.go:148
17:44:27 level=info msg="task 1371 repo is <org>/<repo> ..." runner.go:333
17:44:27 level=debug msg="Worker 0 started" executor.go:101
17:44:27 level=debug msg="Worker 0 executing task 1" executor.go:105
... job runs ...
level=debug msg="Worker 0 finished (1 tasks executed)" executor.go:119
After Worker 0 finished, the next task normally arrives within seconds to a few minutes
(observed gaps on the same day: 19s, 6m18s, etc.), each time re-entering
task N repo is ... → Worker 0 started.
Failure cycle
17:36:31 level=debug msg="Worker 0 finished (1 tasks executed)" executor.go:119 <-- last log line
17:38:13 server marks job 1250 as in_progress (task row created)
(no "task 1250 repo is ..." line)
(no "Worker 0 started" line)
journalctl for the runner unit: -- No entries --
17:44:17 external watchdog restarts the runner (job had been stuck 5m46s)
17:44:19 declare successfully
17:44:27 task 1371 ... -> Worker 0 started -> executing <-- recovers immediately
Job state as seen through the API while stuck:
job 1250: in_progress, started_at 2026-08-01T09:38:13Z
step: queued Run actions/checkout@v7
step: queued (6 more steps, all queued)
Process state while stuck
The runner is not crashed, hung on CPU, or disconnected:
systemctl is-active → active
/proc/<pid>/status → State: S (sleeping), Threads: 13
- 4 ESTABLISHED TCP connections to the Gitea instance on :443
- Total CPU consumed over ~2h wall clock: ~11s (i.e. idle polling, not spinning)
So the process is alive and still connected — it simply never surfaces the assigned task.
Frequency
Measured on one day with 44 workflow runs: 8 occurrences ≈ 18% of runs.
⚠️ Rates must be normalised per-run; raw counts are dominated by daily activity
(the same instance showed 1/4 = 25% and 1/2 = 50% on two quieter days).
What we ruled out
| Hypothesis |
How it was excluded |
tasksVersion staleness (#31074 family) |
We carry a local patch forcing TasksVersion: 0 in internal/app/poll/poller.go (verified present in the built derivation via --replace-fail). Rate stayed ~18%. |
| Concurrency / capacity exhaustion |
One failure occurred with zero concurrent runs (previous run started 71 min earlier, next one 40 min later). |
| Hardware / memory |
Host had RAM replaced and rebooted mid-day; failures occurred both before and after the reboot. |
| Network loss |
4 ESTABLISHED connections to the server during the stuck window. |
| Runner crash / restart loop |
Process alive, same PID throughout the stuck window, State: S. |
Relation to existing issues
What would help narrow it down
debug level does not log the FetchTask round-trip itself, so we cannot see whether the runner
received a task payload and dropped it, or never received one despite the server having assigned it.
A log line on the fetch response path (even at trace) would make this directly diagnosable.
Happy to run instrumented builds against this instance — it reproduces roughly every 5–6 runs.
Description
A single
act_runner(v2.0.0,capacity: 1) periodically stops picking up workwithout any error and without exiting. The server considers the runner healthy and
assigns jobs to it — the job flips to
in_progressand its task row is created —but the runner never logs receiving that task, so every step stays
queuedforeveruntil the runner process is restarted.
This is not the "job stays waiting / never gets assigned" behaviour described in
#33492. Here the job is assigned; it is the runner that never acts on it.
Environment
runner.capacitylog.leveldebug("single runner setups does not seem to be affected"). We reproduce it with one
runner and no parallelism.
Observed behaviour
Normal cycle (from
debuglogs)After
Worker 0 finished, the next task normally arrives within seconds to a few minutes(observed gaps on the same day: 19s, 6m18s, etc.), each time re-entering
task N repo is ...→Worker 0 started.Failure cycle
Job state as seen through the API while stuck:
Process state while stuck
The runner is not crashed, hung on CPU, or disconnected:
systemctl is-active→active/proc/<pid>/status→State: S (sleeping),Threads: 13So the process is alive and still connected — it simply never surfaces the assigned task.
Frequency
Measured on one day with 44 workflow runs: 8 occurrences ≈ 18% of runs.
(the same instance showed 1/4 = 25% and 1/2 = 50% on two quieter days).
What we ruled out
tasksVersionstaleness (#31074 family)TasksVersion: 0ininternal/app/poll/poller.go(verified present in the built derivation via--replace-fail). Rate stayed ~18%.State: S.Relation to existing issues
are not affected. Our jobs are assigned; our setup is single-runner. Different failure mode,
though possibly the same underlying FetchTask path that PR Improve FetchTask reliability / performance #35960 touches.
matches our behaviour closely. The difference is server-side presentation: there the job stayed
waiting; here it becomesin_progress. If the server now creates the task row before the runneracts on it, the same runner-side defect could surface exactly as we observe. Worth checking whether
the Actions Runner processes just one task, then waits forever. (Possible bug in ActionTasksVersion) #31074 fix regressed or was incomplete for v2.0.0.
What would help narrow it down
debuglevel does not log the FetchTask round-trip itself, so we cannot see whether the runnerreceived a task payload and dropped it, or never received one despite the server having assigned it.
A log line on the fetch response path (even at
trace) would make this directly diagnosable.Happy to run instrumented builds against this instance — it reproduces roughly every 5–6 runs.