Skip to content

Commit 35fb765

Browse files
committed
Merge branch 'fix/pgwatch-scrape-sample-limit' into 'main'
fix(monitoring): raise pgwatch scrape sample_limit Closes #343 See merge request postgres-ai/postgresai!404
2 parents 4b7f75f + b744357 commit 35fb765

2 files changed

Lines changed: 29 additions & 5 deletions

File tree

config/prometheus/prometheus.yml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,14 @@ scrape_configs:
1515
scrape_interval: 30s # How often to scrape PGWatch
1616
scrape_timeout: 25s # Timeout for each scrape (must be < scrape_interval)
1717
metrics_path: /pgwatch
18-
sample_limit: 10000 # Safety net: allows full preset + top-100 pgss while rejecting cardinality explosions
18+
# Backstop against a runaway cardinality explosion — NOT a working ceiling.
19+
# sample_limit is all-or-nothing: one sample over the cap and the entire
20+
# scrape is discarded and this target goes up=0. It never truncates, so a
21+
# snug limit costs every pgwatch series at once, silently. A `full` preset
22+
# on a large database reaches ~12.7k samples in steady state, which the
23+
# previous 10000 rejected outright. The real cardinality control is the
24+
# per-metric top-100 cap in config/pgwatch-prometheus/metrics.yml.
25+
sample_limit: 50000
1926

2027
# Self-monitoring: Victoria Metrics internal metrics
2128
# Note: VictoriaMetrics expands percent-brace env vars in this file (not standard Prometheus)
@@ -57,6 +64,6 @@ scrape_configs:
5764
# Safety net only — the per-metric LIMIT 100 in pgwatch metrics.yml
5865
# is the primary cardinality control. Each active queryid emits ~8-9
5966
# labeled samples, so 500 would cap at ~55-60 queryids and silently
60-
# drop the whole scrape on any busy cluster. 5000 is half of the
61-
# /pgwatch limit and gives ~550 queryids of headroom.
67+
# drop the whole scrape on any busy cluster. 5000 gives ~550 queryids
68+
# of headroom, well clear of what the top-100 caps can produce.
6269
sample_limit: 5000

tests/compliance_vectors/test_mr219_monitoring_guards.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,19 @@ def _duration_seconds(value):
1818

1919

2020
def test_pgwatch_sample_limit_allows_capped_full_preset():
21+
"""`sample_limit` is all-or-nothing: one sample over the cap and the WHOLE
22+
scrape is discarded and the target goes `up=0`. It does not truncate.
23+
24+
So the limit must sit well above the largest cardinality normal operation
25+
can legitimately produce — a `full` metric preset on a large database runs
26+
to ~12.7k samples in steady state, which the previous 10000 cap silently
27+
rejected in full, taking every pgwatch series with it.
28+
29+
The real cardinality control is the per-metric top-100 cap in
30+
config/pgwatch-prometheus/metrics.yml. `sample_limit` is only the backstop
31+
against a runaway explosion, so it keeps an upper bound too — it must not
32+
be removed outright.
33+
"""
2134
prometheus = yaml.safe_load(
2235
(PROJECT_ROOT / "config/prometheus/prometheus.yml").read_text()
2336
)
@@ -26,8 +39,12 @@ def test_pgwatch_sample_limit_allows_capped_full_preset():
2639
if job["job_name"] == "pgwatch-prometheus"
2740
)
2841

29-
assert pgwatch_job["sample_limit"] >= 10000
30-
assert pgwatch_job["sample_limit"] < 50000
42+
# Headroom over the observed full-preset steady state, not a snug fit:
43+
# cardinality grows with the monitored schema, and the failure mode is
44+
# total silent loss rather than partial degradation.
45+
assert pgwatch_job["sample_limit"] >= 50000
46+
# Still a backstop, not an open door.
47+
assert pgwatch_job["sample_limit"] <= 200000
3148

3249
query_info_job = next(
3350
job for job in prometheus["scrape_configs"]

0 commit comments

Comments
 (0)