m3/org/openalice-scheduler

openalice-scheduler

[Atlas card](https://atlas.blal.pro/repos/openalice-scheduler)

Features
17
Status
·unknown
Last activity
1mo ago
Branch
mvp

Architecture rating

C1mo ago
consistencyB

Adopts openalice-axum-common substrate (cors_from_env_or_default, verify_internal_secret, MetricsBuilder) matching sibling services; clean GpuProvider trait + ordered-policy abstraction, zero cycles. Minor env drift: CORS_ORIGINS + RUST_LOG declared-unused (drift 80).

observabilityB

/health + /metrics (Prometheus via shared MetricsBuilder), #[tracing::instrument] on handlers, TraceLayer, opt-in OTLP→Jaeger/Tempo with service.name/version and logs-only fallback. Strong, but metrics are 3 bare gauges — no provision-latency/failure counters or histograms.

docsB-

Valid manifest (100), 17 features, dense @feature annotations + rich in-code architecture comments (sweeper/two-phase release/OTLP rationale), AGENTS.md present. Dragged down by a thin README (just an Atlas-card link) and 61 missing docstrings flagged by inspector.

securityB-

Every /v1 endpoint gated by shared verify_internal_secret (X-Internal-Secret); release adds X-Lease-Owner 403 ownership check; CORS from env; secret required-or-bail at boot. No rate-limiting, binds 0.0.0.0, no security headers; low injection/SSRF surface (provisions to fixed RunPod/Docker only).

reliabilityC-

RunPod client 30s timeout, 30s TTL sweeper reaps expired leases idempotently, release tolerates already-gone (404), provision maps to 502/503. But NO graceful shutdown on SIGTERM (axum::serve, no drain), no retries on transient RunPod/Docker errors, and in-memory registry orphans cloud pods on crash/restart.

testingD

6 integration tests on stub provider cover policy first-available, registry round-trip, TTL sweep, and owner_id propagation — but zero coverage of HTTP handlers: the verify_internal_secret gate and the 403 owner-mismatch path are untested, and RunPod/local-docker drivers have no tests (avg complexity 2.21).

data layerD

No datastore at all — leases held in in-memory Arc<RwLock<HashMap>>; manifest owns zero tables, no migrations/persistence/RLS/GDPR. owner_id tag is the only data discipline; state (and paid-pod tracking) is lost on restart by design but axis-weak.

source · auto-grader-2026-06-16

Ecosystem manifest

.atlas-deps.yml

GPU/compute lease service — acquire/release/list workers from local-Docker or RunPod backends for renderer and anim workloads.

Runtime deps
  • via cargo
    Shared axum plumbing: verify_internal_secret, cors_from_env_or_default, MetricsBuilder.
  • openalice-animhttpoptional
    via INTERNAL_SECRET
    anim service calls POST /v1/lease + DELETE /v1/lease/{id} to provision and release anim workers.
  • via INTERNAL_SECRET
    live-control calls POST /v1/lease + DELETE /v1/lease/{id} to provision and release renderer workers.
Consumed env
  • INTERNAL_SECRET
  • SCHEDULER_PORT
  • PROVIDERS
  • RENDERER_IMAGE
  • ANIM_IMAGE
  • DOCKER_NETWORK
  • RUNPOD_API_KEY
  • RUNPOD_RENDERER_TEMPLATE
  • RUNPOD_ANIM_TEMPLATE
  • OTEL_EXPORTER_OTLP_ENDPOINT
  • OTEL_SERVICE_NAME
  • RUST_LOG
  • CORS_ORIGINS
Exposes
  • docker_image: openalice-scheduler
  • http_endpoint: POST /v1/lease
  • http_endpoint: DELETE /v1/lease/{lease_id}
  • http_endpoint: GET /v1/leases
  • http_endpoint: GET /health
  • http_endpoint: GET /metrics
Env drift · manifest ⇄ code

Atlas grepped the repo's source for env reads (rust env::var · ts process.env · py os.environ · shell $VAR) and diffed against the manifest's consumes_env. Two lists below: stale declarations and undeclared reads.

Manifest declares, code unused
  • CORS_ORIGINS
  • RUST_LOG
Observed reads: 11 · declared: 13

Roadmap · what's planned next

9% avg5 goals

Code composition

tokei · loc
1.1kloc
  • Rust96.7%
  • TOML3.3%
  • Rust96.7%· 1,024
  • TOML3.3%· 35
Language% codecodecommentsblanksfiles
Rust96.7%1,024391069
TOML3.3%35541
Markdown0.0%098452

Telemetry ribbon · last 90 days

12 events
MAYJUNJUL2026-05-21 · commit · new commit c38082b → 14fca5d2026-05-21 · commit · new commit 14fca5d → 7d6814c2026-05-21 · commit · new commit 7d6814c → 34398092026-05-22 · commit · new commit 3439809 → 5c80ba62026-05-22 · commit · new commit 5c80ba6 → 9d6a2c92026-05-24 · kind · kind reclassified · service → infrastructure2026-05-24 · kind · kind reclassified · infrastructure → service2026-05-28 · kind · kind reclassified · service → infrastructure2026-05-28 · kind · kind reclassified · infrastructure → service2026-06-16 · commit · new commit 9d6a2c9 → 12492902026-07-16 · kind · kind reclassified · service → infrastructure2026-07-17 · kind · kind reclassified · infrastructure → serviceNOW
commitmanifestlifecyclekind

scheduler/api

3 features
  • scheduler.api.acquire
    src/main.rs:257
    POST /v1/lease — X-Internal-Secret gated. Selects the first available provider via `OrderedFirstAvailable` policy, calls `provider.provision(req)`, records the resulting `Lease` in the in-memory `LeaseRegistry`, and returns `{ lease, provider }`. Returns 503 if no provider can satisfy the request, 502 on provision failure. [tracing::instrument(
  • scheduler.api.list
    src/main.rs:381
    GET /v1/leases — X-Internal-Secret gated. Returns the full snapshot of active `Lease` objects held in the in-memory registry at the moment of the call. Used by live-control and ops tooling to inspect pool occupancy.
  • scheduler.api.release
    src/main.rs:308
    DELETE /v1/lease/{lease_id} — X-Internal-Secret gated. Verifies `X-Lease-Owner` when `Lease.owner_id` is set (403 on mismatch). Atomically removes the lease from the registry via `registry.take`, calls `provider.release(lease)` to stop + remove the container (Docker) or terminate the pod (RunPod), and returns 204 No Content. Returns 404 if the lease is not found. [tracing::instrument(

scheduler/health

1 feature
  • scheduler.health.endpoint
    src/main.rs:394
    GET /health returns `{status:"ok", service:"openalice-scheduler"}` — Traefik liveness probe; un-gated so the probe doesn't depend on the internal secret being mounted into the load balancer.
    api:GET /health
    since 0.1.0

scheduler/metrics

1 feature
  • scheduler.metrics.endpoint
    src/main.rs:408
    GET /metrics — Prometheus text with `scheduler_up`, `scheduler_active_leases` (current registry size), and `scheduler_providers` (configured driver count); built via openalice-axum-common's MetricsBuilder for parity with sibling services.
    api:GET /metrics
    since 0.1.0

scheduler/policy

1 feature
  • scheduler.policy.ordered-first-available
    src/policy.rs:9
    Ordered first-available provider selection — iterates declared providers in PROVIDERS order and picks the first whose `available(req)` returns true. Cheapest-first / geo-aware revs are roadmap.
    since 0.1.0

scheduler/provider

3 features
  • scheduler.provider.local-docker
    src/providers/local_docker.rs:12
    Default GpuProvider — spawns renderer/anim containers via bollard on the host Docker engine, attaches them to DOCKER_NETWORK, and tears them down on release. Handles gpu=none + gpu=entry; the free-tier path.
    since 0.1.0
  • scheduler.provider.runpod
    src/providers/runpod.rs:11
    RunPod GraphQL driver — provisions renderer/anim pods via podFindAndDeployOnDemand (non-interruptable) and releases via podTerminate. Activated when `runpod` is listed in PROVIDERS and RUNPOD_API_KEY is set.
    since 0.1.0
  • scheduler.provider.trait
    src/provider.rs:11
    `GpuProvider` defines the two-method contract (`provision` + `release`) all backends must implement plus a cheap `available` probe used by the policy layer. Public types `LeaseRequest`, `Lease`, `WorkerKind` (`renderer` | `anim`), and `GpuClass` (`none` | `entry` | `mid` | `high`) are the only wire types the scheduler API exposes; callers and providers share nothing else.

scheduler/providers

1 feature
  • scheduler.providers.build
    src/main.rs:200
    build_providers reads the `PROVIDERS` env (comma-separated names, default "local-docker"), instantiates each driver in declared order, and returns them as `Vec<Arc<dyn GpuProvider>>` for the policy layer; bails when an unknown name is listed or no driver is configured.
    since 0.1.0

scheduler/registry

3 features
  • scheduler.registry.spawn-sweeper
    src/leases.rs:116
    spawn_sweeper boots the 30-second TTL reaper Tokio task; first tick is dropped so the sweep only runs on the periodic cadence, not at startup before any lease exists.
    since 0.1.0
  • scheduler.registry.store
    src/leases.rs:28
    LeaseRegistry — in-memory `Arc<RwLock<HashMap<lease_id, ActiveLease>>>` shared across HTTP handlers + the sweeper task; `record` / `take` / `list` / `count` are the only mutation/read surface so consistency between provider drivers and the API stays tight.
    type:LeaseRegistry
    since 0.1.0
  • scheduler.registry.sweep
    src/leases.rs:10
    Background TTL sweeper spawned at startup via `spawn_sweeper`. Every 30 seconds `sweep_once` reads expired leases (expires_at ≤ now), atomically removes each entry, and calls `provider.release(lease)` on the owning driver. A failed release is logged as a warning; the entry is still removed so the registry stays consistent. Bounds cloud costs on crashed callers.

scheduler/service

1 feature
  • scheduler.service.crate
    src/lib.rs:5
    GPU/compute lease service for OpenAlice. Exposes a uniform HTTP API (POST /v1/lease, DELETE /v1/lease/{id}, GET /v1/leases) so upstream services (openalice-live-control, openalice-anim) provision and release renderer + anim workers without caring which backend (local-docker, RunPod, Modal, …) runs the work. Lifecycle: provision → optional heartbeat via TTL → explicit release or 30 s sweep auto-reap.

scheduler/tracing

1 feature
  • scheduler.tracing.otlp
    src/main.rs:67
    init_otel_tracer wires an OTLP gRPC span exporter (opt-in via `OTEL_EXPORTER_OTLP_ENDPOINT`) and tags every span with `service.name` + `service.version` so traces land in Jaeger/Tempo under the right service without per-deploy config; failure falls back to logs-only.
    since 0.1.0

scheduler/types

2 features
  • scheduler.types.lease
    src/provider.rs:121
    Lease wire shape — { lease_id, provider, kind, endpoint, created_at, expires_at, provider_token, owner_id }; `provider_token` is the opaque id (container id / RunPod pod_id) the driver needs to release.
    type:Lease
    since 0.1.0
  • scheduler.types.lease-request
    src/provider.rs:57
    LeaseRequest wire shape — { kind (renderer|anim), gpu (none|entry|mid|high), correlation_id, owner_id, region, ttl_seconds (≤8h), env map }; default ttl=3600, default gpu=None; carries `owner_id` so release can enforce X-Lease-Owner.
    type:LeaseRequest
    since 0.1.0