GitHubActionCacheServer

module
v1.0.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 27, 2026 License: MIT

README

GitHubActionCacheServer

License Release Dockerhub

A Go implementation of the GitHub Actions cache service protocol for self-hosted runners. It implements the cache v2 API surface used by actions/cache, stores cache metadata in SQL, and stores cache objects on a local filesystem or S3.

The goal is to address performance bottlenecks while staying compatible with falcondev-oss/github-actions-cache-server by default. The only intentional compatibility gap is GCS storage support.

Quick Start

Run locally with SQLite and filesystem storage:

go mod download
go generate ./internal/ent
API_BASE_URL=http://localhost:3000 go run ./cmd/server

The server listens on :3000 by default. Health checks:

curl http://localhost:3000/
curl http://localhost:3000/health

For local protocol tests only, SKIP_TOKEN_VALIDATION=true can be used to accept unsigned or test JWTs. Do not use it for production.

Docker

Image: mmx233/action-cache-server

Build the image:

docker build -t mmx233/action-cache-server .

Run a disposable local instance:

docker run --rm -p 3000:3000 \
  -e API_BASE_URL=http://localhost:3000 \
  -e DB_SQLITE_PATH=/tmp/cache-server/sqlite.db \
  -e STORAGE_FILESYSTEM_PATH=/tmp/cache-server/filesystem \
  mmx233/action-cache-server:latest

For persistent deployments, mount a writable data directory and point DB_SQLITE_PATH and STORAGE_FILESYSTEM_PATH at that directory, or use an external SQL database plus S3 storage.

Configuration

Server
Variable Default Description
ADDR :3000 HTTP listen address.
API_BASE_URL empty Public base URL used when generating signed upload and download URLs.
DEFAULT_ACTIONS_RESULTS_URL https://results-receiver.actions.githubusercontent.com Upstream target for fallback proxy requests.
DEBUG false Enables debug log level.
Authentication
Variable Default Description
GITHUB_ACTIONS_TOKEN_ISSUER https://token.actions.githubusercontent.com Expected JWT issuer.
GITHUB_ACTIONS_TOKEN_JWKS_URL https://token.actions.githubusercontent.com/.well-known/jwks JWKS URL for JWT verification.
SKIP_TOKEN_VALIDATION false Parses JWTs without signature verification. Intended for tests only.

The token must contain repository_id and an ac claim with cache scopes. A scope with permission >= 2 is required for saves; scopes with permission >= 1 are used for restores.

Database
Variable Default Description
DB_DRIVER sqlite sqlite, postgres, or mysql.
DB_SQLITE_PATH .data/sqlite.db SQLite database path.
DB_POSTGRES_URL empty Full PostgreSQL DSN.
DB_POSTGRES_DATABASE empty PostgreSQL database when not using DB_POSTGRES_URL.
DB_POSTGRES_HOST empty PostgreSQL host when not using DB_POSTGRES_URL.
DB_POSTGRES_PORT 5432 PostgreSQL port.
DB_POSTGRES_USER empty PostgreSQL user.
DB_POSTGRES_PASSWORD empty PostgreSQL password.
DB_MYSQL_DATABASE empty MySQL database.
DB_MYSQL_HOST empty MySQL host.
DB_MYSQL_PORT 3306 MySQL port.
DB_MYSQL_USER empty MySQL user.
DB_MYSQL_PASSWORD empty MySQL password.

Schema migrations run automatically at startup.

Storage
Variable Default Description
STORAGE_DRIVER filesystem filesystem or s3.
STORAGE_FILESYSTEM_PATH .data/storage/filesystem Root directory for filesystem storage.
STORAGE_S3_BUCKET empty S3 bucket name. Required for S3 storage.
AWS_REGION us-east-1 S3 region.
AWS_ENDPOINT_URL empty Custom S3-compatible endpoint, such as MinIO.
STORAGE_S3_FORCE_PATH_STYLE true Uses path-style S3 addressing.
STORAGE_S3_KEY_PREFIX gh-actions-cache Prefix for all S3 keys.
STORAGE_S3_UPLOAD_PART_SIZE_BYTES 5242880 S3 upload part size and threshold in integer bytes. Minimum 5242880 bytes (5 MiB); lower values fail startup.
STORAGE_S3_UPLOAD_CONCURRENCY 1 S3 transfer manager upload worker count per object.
STORAGE_S3_MULTIPART_ABORT_TIMEOUT 30s Timeout for aborting failed S3 multipart uploads.

S3 credentials are loaded through the AWS SDK default credential chain.

For S3 deployments, configure an AbortIncompleteMultipartUpload bucket lifecycle rule. It cleans up multipart uploads left incomplete if the server exits during composition; verify lifecycle support when using an S3-compatible endpoint.

An AWS S3 lifecycle configuration can scope the rule to the cache prefix:

{
  "Rules": [
    {
      "ID": "abort-incomplete-cache-uploads",
      "Status": "Enabled",
      "Filter": { "Prefix": "gh-actions-cache/" },
      "AbortIncompleteMultipartUpload": { "DaysAfterInitiation": 1 }
    }
  ]
}
Cache Behavior
Variable Default Description
ENABLE_DIRECT_DOWNLOADS false When using S3, presigns eligible cache objects instead of proxying their downloads through the server.
DOWNLOAD_URL_SIGNING_SECRET generated at startup HMAC secret for local signed download URLs. Set a stable value for multi-instance or restart-safe deployments.
CACHE_MERGE_CONCURRENCY CPU count Maximum number of concurrent S3 materializations. Values below 1 fall back to CPU count.

Local signed download URLs and S3 direct download URLs expire after 10 minutes. Single-part S3 caches are presigned directly. Multi-part caches are presigned after composition when all non-final parts satisfy the backend's multipart upload size constraints (5 MiB on AWS S3); unsupported layouts transparently fall back to server-proxied downloads.

Cleanup
Variable Default Description
DISABLE_CLEANUP_JOBS false Disables background cleanup jobs.
CACHE_CLEANUP_OLDER_THAN_DAYS 90 Deletes cache storage locations not downloaded within this many days.

Cleanup intervals:

  • abandoned uploads: every 5 minutes
  • pending physical storage deletions: every 5 minutes
  • expired cache entries: every 24 hours
  • orphan storage locations: every 24 hours
  • superseded parts: every hour, once the merged representation is at least one hour old

Physical folder deletion uses a transactional database outbox. A failed or interrupted filesystem/S3 deletion remains queued and is retried by the cleanup worker with exponential backoff from 5 minutes up to 24 hours. HTTP request paths only enqueue deletion work, and database transactions are never held open across storage I/O.

Management API
Variable Default Description
MANAGEMENT_API_KEY empty Enables management endpoints when set. Protected endpoints require X-Api-Key.

Endpoints:

  • GET /management-api/_docs
  • GET /management-api/_docs/spec.json
  • GET /management-api/cache-entries/
  • DELETE /management-api/cache-entries/
  • GET /management-api/cache-entries/match
  • GET /management-api/cache-entries/:id
  • DELETE /management-api/cache-entries/:id
  • GET /management-api/storage-locations/:id
  • DELETE /management-api/storage-locations/:id
  • POST /management-api/_rpc
  • POST /management-api/_rpc/*procedure

Development

Generated Ent code is intentionally ignored by git. Generate it before building or testing from a clean checkout:

go mod download
go generate ./internal/ent
go test ./...

External integration coverage can be run when the required services are available:

E2E_POSTGRES_URL='postgres://cache:cache@127.0.0.1:5432/cache_test?sslmode=disable' \
E2E_MYSQL_HOST=127.0.0.1 \
E2E_MYSQL_DATABASE=cache_test \
E2E_MYSQL_USER=cache \
E2E_S3_ENDPOINT_URL=http://127.0.0.1:9000 \
E2E_S3_BUCKET=cache-test \
go test ./e2e -run 'TestExternal(Postgres|MySQL|S3MinIO)SaveAndRestore' -count=1

Targeted data-path benchmarks cover filesystem whole-cache upload/download, Azure block commit, ordered-parts versus merged downloads, concurrent runners, and S3 server-side composition:

go test ./internal/cache ./internal/storage -run '^$' -bench 'Benchmark(Filesystem|Azure|S3)' -benchmem -count=5

Streaming benchmarks run with 32 KiB, 128 KiB, 256 KiB, and 1 MiB buffers. The concurrent-runner benchmark also reports p95 latency and peak process RSS; the deterministic S3 protocol benchmark reports and asserts SDK HTTP requests per composition. When E2E_S3_ENDPOINT_URL and E2E_S3_BUCKET are configured, the same command also runs composition against that external S3-compatible backend to measure its wall-clock latency.

The repository also contains a Go smoke test for the cache v2 HTTP protocol shape. Full runner-level compatibility should be tested with the patched falcondev runner container and a real GitHub Actions job.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL