Skip to content

Commit 41b883a

Browse files
committed
feat(webapp): make the snapshot store metrics and the append alarm observable locally
The engine metrics never reached the local Prometheus. The collector had no metrics pipeline, so the scrape target that its own configuration describes as carrying every OpenTelemetry metric returned nothing, and Prometheus evaluated no rules because it loaded none. The collector now exports metrics on the port the compose file already publishes, Prometheus loads rule files, and three rules ship with the repo. The first pages on a sustained append failure, which is the one that matters: each failure burns an attempt on the run it touches, so runs exhaust their retry budget from an infrastructure fault rather than anything the task did. Set INTERNAL_OTEL_METRIC_EXPORTER_ENABLED and INTERNAL_OTEL_METRIC_EXPORTER_URL to see the metrics; both are already in .env.example.
1 parent 8d075eb commit 41b883a

4 files changed

Lines changed: 67 additions & 0 deletions

File tree

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Alerting rules for the execution-snapshot store.
2+
#
3+
# These are paging rules, not dashboard panels. A sustained append failure burns an attempt number
4+
# on every state transition, so runs exhaust their retry budget from an infrastructure fault rather
5+
# than from anything the task did. That is silent to the customer until their run fails for good.
6+
groups:
7+
- name: snapshot-store
8+
interval: 30s
9+
rules:
10+
- alert: SnapshotStoreAppendFailing
11+
# Any sustained failure at all, not a rate threshold: one failed append per minute still
12+
# burns one attempt per minute on the runs it touches.
13+
expr: sum(rate(run_engine_snapshot_store_append_failed_total[5m])) > 0
14+
for: 10m
15+
labels:
16+
severity: page
17+
annotations:
18+
summary: "Execution-snapshot appends to Redis are failing"
19+
description: >-
20+
Appends have failed continuously for 10 minutes. Each failure burns an attempt number on
21+
the run it touches, so runs will exhaust their retry budget from infrastructure rather
22+
than task failure. Turn the snapshotStoreMode flag down to off, which takes effect
23+
without a deploy, then investigate the Redis endpoint.
24+
25+
- alert: SnapshotStoreQuarantineFailing
26+
# A quarantine that cannot be applied leaves a run's Redis head permanently behind Postgres.
27+
expr: sum(rate(run_engine_snapshot_store_quarantine_total{outcome="failed"}[10m])) > 0
28+
for: 15m
29+
labels:
30+
severity: page
31+
annotations:
32+
summary: "Execution-snapshot keyspaces cannot be quarantined"
33+
description: >-
34+
A divergent Redis head could not be dropped, so that run keeps a head that is behind
35+
Postgres. Do not move the dial to redis-read while this is firing: a frozen head is
36+
served as if it were current.
37+
38+
- alert: SnapshotStoreSweepNotCompleting
39+
# The sweep is the only reaper for orphaned keyspaces. Its absence is silent by nature.
40+
expr: sum(increase(run_engine_snapshot_store_sweep_pass_total{outcome="completed"}[24h])) == 0
41+
for: 1h
42+
labels:
43+
severity: ticket
44+
annotations:
45+
summary: "No execution-snapshot sweep pass completed in 24 hours"
46+
description: >-
47+
The sweep runs every 6 hours by default, so 24 hours with no completed pass means the
48+
job is not running, is failing, or is losing its lock every pass.

docker/config/prometheus.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ global:
55
scrape_interval: 15s
66
evaluation_interval: 15s
77

8+
# Paging rules live in the repo so they are reviewable and can be checked locally with
9+
# `promtool check rules`. Mounted read-only by docker-compose.extras.yml.
10+
rule_files:
11+
- /etc/prometheus/alerts/*.yml
12+
813
scrape_configs:
914
# Scrape OpenTelemetry Collector's Prometheus exporter
1015
# This includes all OTel metrics (batch queue, fair queue, etc.)

docker/docker-compose.extras.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ services:
9595
restart: always
9696
volumes:
9797
- ./config/prometheus.yml:/etc/prometheus/prometheus.yml:ro
98+
- ./config/alerts:/etc/prometheus/alerts:ro
9899
- prometheus-data:/prometheus
99100
ports:
100101
- "${PROMETHEUS_HOST_PORT:-9090}:9090"

docker/otel-collector-config.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,15 @@ processors:
1212
exporters:
1313
logging:
1414
verbosity: normal
15+
# Serves the collected metrics on :8889/metrics, which docker-compose.extras.yml publishes and
16+
# config/prometheus.yml already scrapes. Without this pipeline that scrape target returns nothing,
17+
# so no OTel metric is visible locally.
18+
prometheus:
19+
endpoint: 0.0.0.0:8889
20+
# Keeps the metric names as OpenTelemetry emitted them, so a rule written against
21+
# run_engine_snapshot_store_* matches without a namespace guess.
22+
resource_to_telemetry_conversion:
23+
enabled: false
1524
otlphttp:
1625
endpoint: "http://host.docker.internal:3030/otel"
1726
compression: none
@@ -26,3 +35,7 @@ service:
2635
receivers: [otlp]
2736
processors: [batch]
2837
exporters: [otlphttp]
38+
metrics:
39+
receivers: [otlp]
40+
processors: [batch]
41+
exporters: [prometheus]

0 commit comments

Comments
 (0)