Skip to content

[API] Add provisioning/pending/start-time metrics and availability dashboard panels - #10625

Open
lloyd-brown wants to merge 3 commits into
masterfrom
lloyd/apiserver-lifecycle-metrics
Open

[API] Add provisioning/pending/start-time metrics and availability dashboard panels#10625
lloyd-brown wants to merge 3 commits into
masterfrom
lloyd/apiserver-lifecycle-metrics

Conversation

@lloyd-brown

@lloyd-brown lloyd-brown commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Summary

image image
  • Adds sky_provision_duration_seconds{cloud,result}: wall-clock time of each provisioning attempt (compute acquisition time), observed around _bulk_provision where the duration was previously only logged. Failures are observed before failover teardown starts, so teardown time is not counted.
  • Adds sky_apiserver_request_pending_seconds{name,schedule_type}: time from request creation to its first execution start. Complements sky_apiserver_queue_wait_seconds (per-enqueue queue residency) by including scheduling preconditions and retry backoff. Observed exactly once per request (guarded on pid being unset), so a --retry-until-up request looping through the retry-requeue path cannot repeatedly re-observe its ever-growing age (the same failure mode [API] Measure executor queue-wait per-enqueue, not since request creation #9988 fixed for the queue-wait metric).
  • Adds sky_apiserver_start_time_seconds: server boot timestamp (uptime = time() - metric). Sourced from the main server process creation time via a custom collector; process_start_time_seconds is unavailable under the multiprocess collector. The boot-check request row (which debug dumps use for uptime) is deliberately not used: schedule_on_boot_check_async swallows RequestAlreadyExistsError, so that row survives fast restarts with a stale created_at.
  • Dashboard (api-server-overview.json): new Scheduling & Provisioning row (Request Pending P95 by request name; Provision Duration P95 + average by cloud/result) and a Server Availability stat in the reworked top row showing both the dashboard-range availability and a fixed trailing-30-day value. Also fixes a grid overlap between the RPS by User and Request duration panels.
  • Docs (api-server-metrics-setup.rst): documents the new metrics, and adds an Availability tracking section with the skypilot-slo recording-rule group backing the 30d value (via the Prometheus subchart's serverFiles), the retention requirement (>= 30d; Prometheus defaults to 15d), and the caveats of quoting the 30d number (no backfill; unmeasured time is not counted; up measures metrics-endpoint reachability, not request success).

Test plan

Ran a local API server (Docker, Postgres, SKY_API_SERVER_METRICS_ENABLED=true, multiprocess mode) with Prometheus + Grafana scraping /metrics:

  • Launched and tore down small Kubernetes clusters: sky_provision_duration_seconds_count{cloud="Kubernetes",result="success"} incremented with plausible sums (~18s first launch, ~5s warm relaunch); P95/avg panel queries return data.
  • Exercised sky status / sky jobs queue and internal daemons: sky_apiserver_request_pending_seconds populated for both the subprocess executor path and the coroutine path, labeled by request name; verified histogram_quantile(0.95, ...) in Prometheus.
  • Restarted the server: sky_apiserver_start_time_seconds matches the new boot within seconds (the boot-check-row approach was verified stale across restarts, which motivated the process-creation-time source).
  • Stopped the server container for ~4 minutes with the recording rules installed: availability stat dropped accordingly for both the range and 30d values; verified the recorded series sky:apiserver_up:max counted the expected number of down-samples.
  • Dashboard JSON validated and loaded in Grafana (10.4 and 12.x panel schemas); all new panels render with data.
  • bash format.sh --files <changed files>: yapf/isort clean, mypy clean, pylint 10.00/10.

🤖 Generated with Claude Code


Devin Review

…nels

Expose three new lifecycle metrics from the API server:

- sky_provision_duration_seconds{cloud,result}: wall-clock time of each
  provisioning attempt (compute acquisition time), observed in
  bulk_provision around the existing timing that was previously only
  logged. Failure attempts are observed before teardown starts.
- sky_apiserver_request_pending_seconds{name,schedule_type}: time from
  request creation to its first execution start. Unlike
  sky_apiserver_queue_wait_seconds (per-enqueue queue residency), this
  includes scheduling preconditions and retry backoff, and is observed
  exactly once per request (guarded on pid being unset) so retry-requeue
  loops cannot re-observe an ever-growing age (see #9988).
- sky_apiserver_start_time_seconds: server boot timestamp, sourced from
  the main server process creation time. The boot-check request row is
  deliberately not used: it survives fast server restarts (the scheduler
  swallows RequestAlreadyExistsError), so its created_at can reflect an
  older boot.

Dashboard: add a Scheduling & Provisioning row (request pending P95,
provision duration P95/avg) and a Server Availability stat to the API
server overview dashboard, and rework the top-row layout to fit it. The
availability stat shows the dashboard-range value and a fixed
trailing-30d value backed by new documented recording rules; docs cover
the rule group, retention requirements, and the caveats of quoting the
30d number.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

Devin Review

Comment thread sky/server/requests/executor.py Outdated
Comment thread sky/provision/provisioner.py
- first-execution detection for sky_apiserver_request_pending_seconds now
  keys on status == PENDING instead of pid: the ExecutionRetryableError
  handler clears pid before requeueing, so every retry looked like a
  first run. The retry/pause path is the only writer of WAITING, so
  PENDING at execution start identifies the first attempt exactly.
- ExecutionPausedError no longer records a provision failure: a pause to
  wait on an external condition is neither success nor failure.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@DanielZhangQD DanielZhangQD left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! @lloyd-brown

Comment thread charts/skypilot/manifests/api-server-overview.json Outdated
Comment thread docs/source/reference/api-server/examples/api-server-metrics-setup.rst Outdated
Comment thread sky/metrics/utils.py Outdated
Comment thread charts/skypilot/manifests/api-server-overview.json Outdated
Comment thread sky/server/requests/executor.py Outdated
Comment thread sky/provision/provisioner.py
… test

- Availability panel selects up{app=~"$app", app!=""} alongside the job
  regex, so annotation-discovered deployments match regardless of release
  name; app!="" keeps an unresolved $app from matching every target. The
  documented recording rule uses an explicit <release>-api placeholder.
- Docs no longer suggest server.retention (the chart already defaults to
  1000d; the 15d default is upstream Prometheus's, noted as such).
- Pending-metric wording corrected everywhere: observed at the first
  execution start, so retry backoff after that start is excluded;
  preconditions are included. Guard extracted into
  _maybe_observe_request_pending with a unit test pinning both
  directions (PENDING observes once, WAITING re-execution observes
  nothing).
- Cancellation (KeyboardInterrupt/SystemExit) no longer recorded as a
  provisioning failure.
- Dashboard second band is four 6-wide panels, removing the 16x8 gap
  left by the RPS-by-User overlap fix.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants