You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 6949841
Browse filesBrowse the repository at this point in the historyBrowse files
docs: average ate.workerpool.workers across replicas before summing (agent-substrate#3193)
The aggregation note from agent-substrate#3056 tells readers to take the `max` across
ate-api-server replicas and then `sum`. As agent-substrate#3162 shows, the replicas
read separate worker caches and can disagree for a few seconds: one
reports `{ate_worker_state="partial"} 3` while the other still reports
`{ate_worker_state="idle"} 3`, so `max by (ate_worker_state)` keeps both
series and the pool sums to 6 workers.
Take the average across replicas instead. It keeps the sum across the
states equal to the pool size; the counts can be fractional for those
few seconds. Updates the registry note and the observability guide. No
code change: the locust collector already reads a single process's
series, and nothing else aggregates this instrument.
Fixesagent-substrate#3162
AI use: Claude Code analyzed the issue and wrote the change and this
description. I reviewed the diff. Codex rebased the branch onto main and
resolved the documentation conflicts.
---------
Signed-off-by: cloudonly <[email protected]>
Copy file name to clipboardExpand all lines: docs/guides/observability.md
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -290,7 +290,7 @@ Agent Substrate emits foundational OpenTelemetry system and server metrics to mo
290
290
|`atelet.snapshot.size`| atelet | histogram | uncompressed allocated size in bytes of each snapshot image written during checkpoint (`st_blocks * 512`, excluding sparse holes in microVM `memory-ranges`) (labels `file.name`, `ate.template.atespace`, `ate.template.name`) |
291
291
|`ate.workerpool.desired_workers`| atecontroller | up/down counter | number of worker pods requested for a WorkerPool, from `spec.replicas` (labels `ate.workerpool.namespace`, `ate.workerpool.name`) |
292
292
|`ate.workerpool.ready_workers`| atecontroller | up/down counter | number of worker pods currently ready for a WorkerPool, from `status.readyReplicas` (labels `ate.workerpool.namespace`, `ate.workerpool.name`) |
293
-
|`ate.workerpool.workers`| ateapi | up/down counter | live worker count per pool, split by state (`idle`/`partial`/`at_capacity`/`unschedulable`) and sandbox class to provide fleet capacity and saturation at a glance. Every ateapi replica reports the whole fleet: take the `max` by pool namespace, pool, state, and sandbox class first, then `sum` (example query below the table) |
293
+
|`ate.workerpool.workers`| ateapi | up/down counter | live worker count per pool, split by state (`idle`/`partial`/`at_capacity`/`unschedulable`) and sandbox class to provide fleet capacity and saturation at a glance. Every ateapi replica reports the whole fleet: take the `avg` by pool namespace, pool, state, and sandbox class first, then `sum` (example query below the table) |
294
294
|`ate.actor.lifecycle.operation.duration`| ateapi | histogram | how long each actor operation (create/resume/suspend/delete/revert) takes and whether it failed (`error.type` present = failure, absent = success); labeled by operation, template, pool (`ate.workerpool.namespace` + `ate.workerpool.name`), sandbox class, snapshot kind on resume, and snapshot fidelity on resume and suspend; already-running resume no-ops are not recorded so the histogram tracks actual activations, not router traffic |
295
295
|`ate.scheduler.assignment.duration`| ateapi | histogram | time of one attempt to assign a worker to an actor, with one record for each resume (ateapi retries an attempt that loses a race for a worker and records only the last attempt), with the outcome (`assigned` / `no_capacity` / `error`), the assigned pool (`ate.workerpool.namespace` + `ate.workerpool.name`) and sandbox class to catch scheduling latency and capacity starvation problems |
296
296
|`ate.actor.restore.duration`| atelet | histogram | how long each phase of a restore takes on the worker node, which is where cold-start latency actually goes once ateapi hands off (labels `ate.snapshot.phase`, `ate.snapshot.kind`, `ate.snapshot.fidelity`, `ate.template.atespace`, `ate.template.name`, `ate.sandbox.class`) |
@@ -313,11 +313,11 @@ For `ate.workerpool.desired_workers` and `ate.workerpool.ready_workers`:
313
313
***Autoscaling Control Loop & Anti-Windup**: `desired - ready > 0` sustained beyond a few minutes indicates undelivered capacity due to node pool exhaustion, quota limits, or stuck worker pods, serving as anti-windup input for demand-reactive capacity scaling.
314
314
315
315
For `ate.workerpool.workers`:
316
-
* Every ateapi replica reports the whole fleet, so a plain `sum` counts each worker once per replica ([#3055](https://github.com/agent-substrate/substrate/issues/3055)). Take the `max` across replicas first, keeping the pool namespace, pool, state, and sandbox class, then `sum`. Workers per pool:
316
+
* Every ateapi replica reports the whole fleet, so a plain `sum` counts each worker once per replica ([#3055](https://github.com/agent-substrate/substrate/issues/3055)). The replicas read separate worker caches and can disagree for a few seconds: a worker that changed state sits under its old state on one replica and its new state on the other ([#3162](https://github.com/agent-substrate/substrate/issues/3162)). Take the `avg` across replicas first, keeping the pool namespace, pool, state, and sandbox class, then `sum`. A `max` would keep that worker under both states and the summed pool outgrows its real size. The average keeps the sum equal to the pool size; the counts can be fractional while the replicas disagree. Workers per pool:
317
317
318
318
```promql
319
319
sum by ("ate.workerpool.namespace", "ate.workerpool.name") (
320
-
max by ("ate.workerpool.namespace", "ate.workerpool.name", "ate.worker.state", "ate.sandbox.class") (
320
+
avg by ("ate.workerpool.namespace", "ate.workerpool.name", "ate.worker.state", "ate.sandbox.class") (
0 commit comments