KEDA adapter for auto-scaling runners https://carverauto.dev
  • Go 94.4%
  • Dockerfile 5.6%
Find a file
Michael Freeman 23b67e0d0c
All checks were successful
CI / test (push) Successful in 18s
Release / release (push) Successful in 2m53s
Publish release artifacts for amd64 only
2026-04-02 19:15:52 -05:00
.forgejo/workflows Publish release artifacts for amd64 only 2026-04-02 19:15:52 -05:00
cmd/forgejo-keda-adapter Add golangci-lint config and clean up adapter 2026-04-02 18:49:12 -05:00
examples/kubernetes Use ServiceRadar Harbor image path 2026-04-02 18:42:11 -05:00
.gitignore Add Go-based Forgejo KEDA adapter 2026-04-02 17:34:52 -05:00
.golangci.yml Add golangci-lint config and clean up adapter 2026-04-02 18:49:12 -05:00
Dockerfile Add Go-based Forgejo KEDA adapter 2026-04-02 17:34:52 -05:00
go.mod Add Go-based Forgejo KEDA adapter 2026-04-02 17:34:52 -05:00
LICENSE Add CI and release automation 2026-04-02 17:40:18 -05:00
README.md Publish release artifacts for amd64 only 2026-04-02 19:15:52 -05:00

Forgejo KEDA Adapter

forgejo-keda-adapter is a small Go service that converts Forgejo runner jobs into a single numeric metric for KEDA's metrics-api scaler.

It polls Forgejo's runner jobs API and exposes a KEDA-friendly response:

{"value":7,"jobs_total":7,"counted_statuses":["running","waiting"]}

The intended module and source location is:

code.carverauto.dev/carverauto/forgejo-keda-adapter

Why This Exists

Forgejo exposes runner jobs as a JSON list, not as a scalar metric. KEDA only needs a number. This adapter is the shim between those two shapes.

The pattern is:

  1. Query Forgejo for runner jobs.
  2. Count jobs in the statuses you care about.
  3. Return {"value": N} over HTTP.
  4. Point a KEDA metrics-api trigger at that endpoint.

No Prometheus exporter or Kubernetes custom metrics adapter is required.

Endpoints

  • GET /jobs
  • GET /healthz

Configuration

  • FORGEJO_JOBS_URL: required
  • FORGEJO_API_TOKEN: required
  • FORGEJO_COUNT_STATUSES: default waiting,running
  • FORGEJO_TIMEOUT_SECONDS: default 3
  • PORT: default 8080

If you only want queued jobs, set:

export FORGEJO_COUNT_STATUSES=waiting

Forgejo API Notes

This was proven against:

/api/v1/admin/runners/jobs

On our Forgejo build, the filtered form with ?labels=... returned null even when jobs existed. The unfiltered admin endpoint returned the correct list, so the working production setup polls the unfiltered admin jobs API.

That means this setup currently works best for a single runner pool. If you run multiple independent pools, you may need stronger server-side filtering than Forgejo currently provides.

Local Run

go run ./cmd/forgejo-keda-adapter

With env:

export FORGEJO_JOBS_URL='https://forgejo.example.com/api/v1/admin/runners/jobs'
export FORGEJO_API_TOKEN='replace-me'
export FORGEJO_COUNT_STATUSES='waiting,running'

Then:

curl http://127.0.0.1:8080/jobs
curl http://127.0.0.1:8080/healthz

Tests

go test ./...

Container Build

docker build -t forgejo-keda-adapter:dev .
docker run --rm -p 8080:8080 \
  -e FORGEJO_JOBS_URL='https://forgejo.example.com/api/v1/admin/runners/jobs' \
  -e FORGEJO_API_TOKEN='replace-me' \
  forgejo-keda-adapter:dev

Kubernetes Example

Example manifests live under examples/kubernetes:

  • deployment.yaml
  • service.yaml
  • scaledobject.yaml

The example ScaledObject targets one counted job per runner pod with delayed scale-down:

  • pollingInterval: 15
  • cooldownPeriod: 300
  • stabilizationWindowSeconds: 300
  • targetValue: 1

CI And Release Automation

This repo now includes Forgejo Actions workflows under .forgejo/workflows:

  • ci.yml: runs go test ./..., builds the binary, and verifies docker build
  • release.yml: on v* tags, builds a linux/amd64 release tarball, pushes the linux/amd64 container image to registry.carverauto.dev/serviceradar/forgejo-keda-adapter, and creates or updates a Forgejo release

Required secrets:

  • HARBOR_ROBOT_USERNAME
  • HARBOR_ROBOT_SECRET
  • FORGEJO_TOKEN

License

This project is licensed under MIT. See LICENSE.