Skip to content

controller: 0.25-0.8 of a CPU core continuously while every worker is idle (0.1.24, Windows host) #328

Description

@kyle-sexton

Summary

ci-runner-controller.exe (0.1.24) burns roughly 0.25-0.8 of a CPU core continuously while every worker is idle. Over a 24 h 17 m uptime on melo-lap-001 it had accumulated 62,461 CPU-seconds (about 0.71 cores averaged over the whole day) with zero jobs assigned for most of that window. In a 10 s live sample it was the single largest CPU consumer on the host at 2.5% of a 32-thread machine, ahead of Defender (2.0%) and Docker Desktop (0.4%).

Observations

  • Host: melo-lap-001 (i9-13980HX, 24C/32T, Windows 11 26200), AC power, Docker Desktop running, WSL 2.
  • ci-runner host status: desired mode enabled, phase ready, six workers all state=idle job=-, pools assigned=0.
  • ci-runner host doctor --json: every check healthy except the advisory pending-reboot; listeners acknowledged, capacity 11 and 1, assigned 0.
  • Config: controller.reconcileInterval: 5s, shutdownPollInterval: 1s, localProbeTimeout: 15s, desktopProbeTimeout: 45s.
  • Over a 15 s window with the controller idle: CPU delta 3.41 s (0.23 cores); no child processes were observed being spawned in that window (no docker, wsl, gh, or shell children appeared), so the cost is inside the controller process itself rather than in CLI probes it launches.
  • %LOCALAPPDATA%\ci-runner\diagnostics holds 5,455 entries and logs 2,750; new *-diag.tar.gz and *-resources.json pairs were being written every few minutes for idle workers (four pairs between 01:14 and 01:20 UTC).

Why it matters

This host doubles as an interactive workstation running several concurrent Claude Code sessions, where the dominant latency term is process-creation contention. A permanent 0.25-0.8 core of background CPU from an idle control plane adds directly to that contention and to fan and battery load on the laptop.

Suggested investigation

  1. Profile the reconcile loop at reconcileInterval: 5s with all workers idle: which calls run every tick (Docker API list/inspect per worker, GitHub listener polling, capacity reconciliation, diagnostics capture)?
  2. Consider an idle back-off: lengthen the reconcile interval when assigned=0 has been stable for N ticks, returning to 5 s on the first job or listener transition.
  3. Check whether per-worker diagnostics capture is meant to run while workers are idle, and whether the diagnostics directory has a retention sweep.
  4. Expose the controller's own tick cost (or CPU seconds per reconcile) in host status so this can be watched without external sampling.

Verification

Reproduce by sampling Get-Process ci-runner-controller | Select-Object CPU twice 15 s apart with the fleet idle, or via \Process(ci-runner-controller)\% Processor Time in Get-Counter. Expected after a fix: well under 0.05 cores while idle.

No linked issue.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-humanHuman-in-the-loop required; autonomous sessions must not resolve items carrying this.priority: highSignificant impact, or blocks an imminent release; staff this cycle.status: needs-decisionAwaiting a human or maintainer judgment call.work-class: structuralRefactors, migrations, contract changes; cross-cutting and hard to reverse.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions