Skip to content

imagecache: add ate.imagecache.requests hit and miss telemetry (#831) - #834

Open
Jeff Luo (JeffLuoo) wants to merge 1 commit into
agent-substrate:mainfrom
JeffLuoo:imagecache-requests-metric
Open

imagecache: add ate.imagecache.requests hit and miss telemetry (#831)#834
Jeff Luo (JeffLuoo) wants to merge 1 commit into
agent-substrate:mainfrom
JeffLuoo:imagecache-requests-metric

Conversation

@JeffLuoo

@JeffLuoo Jeff Luo (JeffLuoo) commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Add the ate.imagecache.requests counter.

ate.imagecache.outcome (new key in internal/ateattr)

Value Meaning
hit the node holds a complete image record: each layer directory that the record names is present
miss the lookup must pull
error the lookup failed; the only outcome that carries error.type
cancelled, timeout the caller gave up, so the cache is not at fault

A failed lookup is neither a hit nor a miss, so it gets its own outcome, as
no_free_worker does on ate.scheduler.outcome. cancelled and timeout are
outcomes for the same reason they are on ate.router.outcome. The hit ratio is
therefore hit / (hit + miss), with failures and abandoned lookups out of the
denominator.

error.type — set only on the error outcome.

Value Meaning
404, 401, 429, ... the registry rejected the request; its own HTTP status, reported verbatim
_OTHER the failure carries no status of its own

Fixes #831

It's a good idea to open an issue first for discussion.

  • Tests pass
  • Appropriate changes to documentation are included in the PR

@JeffLuoo
Jeff Luo (JeffLuoo) force-pushed the imagecache-requests-metric branch 2 times, most recently from d5887fa to 5ad0822 Compare August 10, 2026 20:47
@JeffLuoo

Copy link
Copy Markdown
Collaborator Author

Also cc Krisztian F (@krisztianfekete) to review it as well.

@JeffLuoo
Jeff Luo (JeffLuoo) force-pushed the imagecache-requests-metric branch 2 times, most recently from c174674 to f34f9d5 Compare August 11, 2026 14:13
Comment thread internal/imagecache/metrics.go
Comment thread docs/observability.md Outdated
Comment thread internal/ateattr/ateattr.go Outdated
Comment thread docs/observability.md Outdated
…-substrate#831)

The node-local OCI image cache sent no telemetry. The cache is on the
Resume path: atelet calls `Store.EnsureImage` before it makes the OCI
bundle for an actor. A hit costs no network I/O. A miss causes a pull
and an unpack, which takes tens of seconds for a large image. Thus the
hit ratio of a node is a leading indicator of Resume latency, but an
operator could not see it.

Add the `ate.imagecache.requests` Int64Counter (unit `{request}`),
emitted by atelet. Each `EnsureImage` lookup counts one datapoint:

* `ate.imagecache.outcome` (new key): `hit` when the node holds a
  complete image record — each layer directory that the record names is
  present — and `miss` when the lookup must pull. A failed lookup is
  neither, so it gets its own outcome, as no_free_worker does on the
  scheduler: `error` is a failed lookup whatever the cause (the registry,
  the ref, or the node), `cancelled` and `timeout`
  are the caller giving up, which ate.router.outcome also reports as
  outcomes. The hit ratio is thus hit / (hit + miss), with failures and
  abandoned lookups out of the denominator.
* `error.type`: set only on the `error` outcome, and only from the
  registry's own HTTP status for its rejection, which is the one domain
  status this path has, as the gRPC code is for ateapi. transport.Error
  reports whatever the remote returned, so an allow-list bounds the
  label: 401, 403, 404, 429 and the 5xx set, each with its own operator
  action. Each other status, and each failure that carries none, reports
  `_OTHER`, the OTel registry's fallback. The atelet log names what
  broke, and ate.actor.restore.duration attributes it to the oci_unpack
  phase with the template beside it.

The counter carries no identity labels. The layer pool is node state
that each actor on the node shares, whatever its template or its sandbox
class, so a class label would split one cache state into per-class
series and give the pull to the class that asked first. The node and the
pod already arrive as resource attributes, which is what per-node
analysis of the hit ratio needs.

`EnsureImage` records the datapoint in a deferred call, on a context that
survives cancellation: a cancelled pull was started and paid for, and to
drop it would hide a node that cancels each Resume.

The store reports only when the caller gives it a meter (`WithMeter`), so
the validation tool and the tests need no metrics pipeline.

Tests: `internal/imagecache/metrics_test.go` collects the counter through
a ManualReader-backed provider (miss then two hits, the outcome and the
error.type of each failure kind, an unlisted status folding into
`_OTHER`, and a store without a meter). `internal/ateattr` pins
the wire spelling of the new key and its values.

Docs: the metric table and the label notes in `docs/observability.md`.
@JeffLuoo
Jeff Luo (JeffLuoo) force-pushed the imagecache-requests-metric branch from 985efe6 to e1b8a52 Compare August 11, 2026 17:59
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.

Add ate.imagecache.requests: hit and miss telemetry for the node-local image cache

3 participants