Skip to content

Autoscaling: polling and webhooks

Runaway sizes each scale set to demand — the count of busy plus queued jobs — learned through two channels: polling, which always runs, and webhooks, which you can opt into per organization.

By default Runaway polls GitHub roughly every 30 seconds for each org’s queued and in-progress jobs, and sizes the pool to match. Polling works everywhere with no setup:

  • No public exposure. The hub reaches out to GitHub; GitHub never has to reach the hub. A NAT’d homelab hub autoscales out of the box.
  • Near-zero rate-limit cost. Requests are ETag-cached, so an idle org costs almost nothing against your GitHub API budget.

For most homelab and small-team workloads, a ~30-second reaction time is fine.

If you want runners to react faster than the poll interval, you can enable a per-org workflow_job webhook. When GitHub queues a job it tells the hub immediately, instead of the hub waiting for its next poll. Webhooks are an opt-in overlay, not a replacement, and they ask for more from your setup:

  • A publicly reachable hub so GitHub can deliver the webhook.
  • The admin:org_hook scope on that org’s PAT so Runaway can create the webhook.

Webhooks never leave you stranded. When an org has healthy webhook delivery, the autoscaler defers to it; the moment delivery goes quiet or a periodic health check finds the hook broken — deleted, disabled, or failing — polling resumes automatically with no action from you. The two channels feed the same demand calculation, so switching between them changes only the latency, never the behaviour.