Skip to content

act_runner v2.0.0: runner goes silent after Worker finished, server still assigns jobs to it (in_progress + all steps queued) #38737

Description

@SAMYUBA

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-activeactive
  • /proc/<pid>/statusState: 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions