Skip to content

feat(ingest): §6.3 barrier observability — counter, debug log, tests - #45

Merged
zzylol merged 1 commit into
mainfrom
feat/ingest-barrier-observability
Apr 20, 2026
Merged

zzylol merged 1 commit into
mainfrom
feat/ingest-barrier-observability

Conversation

@zzylol

@zzylol zzylol commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

Summary

The §6.3 write-side schema barrier at ingest_handler.rs:156 has been dropping samples for retired/expired agg_ids since Phase 2a, but the drop was silent (no counter, no log line). The e2e that followed #42 tried to confirm the barrier was firing by grepping logs, found nothing, and concluded the barrier wasn't wired — a false alarm that would have sent a bug fix down the wrong path.

This PR is the observability patch: the barrier semantics don't change; we just make it provable that the barrier is doing its job.

What's in this PR

  • IngestState::samples_blocked_by_schema_barrier: AtomicU64. Incremented exactly when is_writable(agg_id) returns false for a metric-matching agg config. (Note: one ingest sample can contribute >1 drop if multiple agg configs match the same metric name and more than one is non-Active.)
  • Per-batch debug! log after the routing loop: total dropped plus per-agg_id breakdown. Aggregated once per batch — a hot ingest path won't flood the log.
  • route_decoded_samples is now pub(crate) so the new test module can exercise it directly without spinning up the full engine.

Why this is a non-fix

The Explore audit confirmed the barrier is already wired on main at ingest_handler.rs:156, both on the Prometheus-remote-write and OTLP paths. The e2e misdiagnosis stemmed from trusting log silence as evidence. Adding the counter means the next e2e can assert `samples_blocked_by_schema_barrier > 0` post-force-expire and know the barrier works, rather than guessing from logs.

Test plan

  • cargo test -p query_engine_rust --lib726 pass (was 723; +3 new tests)
  • cargo clippy --all-targets -- -D warnings — clean
  • cargo fmt --all -- --check — clean
  • New tests:
    • barrier_counter_stays_zero_when_schema_is_active
    • barrier_counter_increments_after_force_expire
    • barrier_counter_ignores_non_matching_metrics

Follow-ups (out of scope here)

  • Expose the counter via the /api/v1/store/metrics or /metrics endpoint so operators can poll it directly.
  • Add a parallel counter on the OTLP ingest paths in drivers/ingest/otel.rs (three barrier checks already live there at lines 375 / 437 / 646).

🤖 Generated with Claude Code

The write-side schema barrier at `ingest_handler.rs` already
drops samples for retired/expired agg_ids (§6.3 of the sketch
DB design), but the drop was silent: no counter, no log. The
e2e after #42 tried to confirm the barrier fires by looking at
the logs and, finding nothing, concluded the barrier wasn't
wired — a false alarm that would have sent a bug report down
the wrong path.

Changes:
- `IngestState::samples_blocked_by_schema_barrier: AtomicU64`.
  Incremented exactly when `is_writable(agg_id)` returns false
  for a matching agg. One ingest sample can contribute more
  than once when multiple agg configs match the same metric.
- Per-batch `debug!` log after the routing loop: total_dropped
  + per-agg_id breakdown. Batched (not per-sample) so a hot
  ingest path doesn't flood the log.
- `route_decoded_samples` promoted to `pub(crate)` so the test
  module can call it directly.
- Three unit tests in `precompute_engine::ingest_handler::tests`:
  - Active schema → counter stays 0.
  - `force_expire` → counter increments by the matching sample
    count in the next batch.
  - Non-matching metrics → counter stays 0 even after expire.

726 lib tests pass (was 723; +3), clippy clean, fmt clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@zzylol
zzylol merged commit fc74113 into main Apr 20, 2026
@zzylol
zzylol deleted the feat/ingest-barrier-observability branch April 20, 2026 14:12
zzylol added a commit that referenced this pull request Apr 20, 2026
Follow-up from #45: the barrier counter was only visible via the
in-process AtomicU64 + debug log, so production deployments
running at INFO had no graphable signal for silent drops.

Changes:
- New `stores::sketch_db::metrics` module with a `CounterVec`
  `queryengine_ingest_samples_blocked_by_schema_barrier_total`,
  keyed by `agg_id`, registered through the global
  `prometheus::default_registry()` so the existing `/metrics`
  handler (`handle_metrics` in drivers/query/servers/http.rs)
  scrapes it automatically.
- Per-agg increment right alongside the atomic bump in
  `route_decoded_samples`, fed by the same per-batch
  `dropped_by_barrier` tally so the counter and the log stay
  consistent.
- New unit test `barrier_prom_counter_increments_per_agg_label`
  that keys on a unique agg_id (9001) to get a deterministic
  baseline in the process-global registry.

Why label by agg_id (not a scalar counter): lets operators
alert on "drops on a specific agg while the registry still
reports that agg Active" — the silent-drop regression the
counter is meant to catch.

729 lib tests pass (+1), clippy clean, fmt clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
zzylol added a commit that referenced this pull request Apr 20, 2026
Follow-up from #45: the barrier counter was only visible via the
in-process AtomicU64 + debug log, so production deployments
running at INFO had no graphable signal for silent drops.

Changes:
- New `stores::sketch_db::metrics` module with a `CounterVec`
  `queryengine_ingest_samples_blocked_by_schema_barrier_total`,
  keyed by `agg_id`, registered through the global
  `prometheus::default_registry()` so the existing `/metrics`
  handler (`handle_metrics` in drivers/query/servers/http.rs)
  scrapes it automatically.
- Per-agg increment right alongside the atomic bump in
  `route_decoded_samples`, fed by the same per-batch
  `dropped_by_barrier` tally so the counter and the log stay
  consistent.
- New unit test `barrier_prom_counter_increments_per_agg_label`
  that keys on a unique agg_id (9001) to get a deterministic
  baseline in the process-global registry.

Why label by agg_id (not a scalar counter): lets operators
alert on "drops on a specific agg while the registry still
reports that agg Active" — the silent-drop regression the
counter is meant to catch.

729 lib tests pass (+1), clippy clean, fmt clean.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
zzylol added a commit that referenced this pull request Apr 20, 2026
)

Follow-up to #45 / #47. The Prometheus `CounterVec`
`queryengine_ingest_samples_blocked_by_schema_barrier_total`
(keyed by `agg_id`) was only bumped by the Prometheus /
VictoriaMetrics remote-write path. The three OTLP barrier
sites in `drivers/ingest/otel.rs` still silently dropped.
This PR completes the observability story — no matter which
driver the DataCollector ships through, a drop increments the
same counter.

Changes:

- **`IngestState::record_barrier_drop(agg_id, count)`** —
  single helper that bumps both the in-process atomic AND the
  Prometheus `CounterVec`. All five ingest drivers funnel
  through it, so the `/metrics` number is a unified sum.
- **`ingest_handler.rs`** — refactored `route_decoded_samples`
  to call the helper instead of maintaining its own inline
  atomic-increment + Prometheus-increment loop. Same batched
  debug-log semantics; fewer moving parts.
- **`otel.rs`** — new local `flush_barrier_drops(state, map,
  driver_tag)` helper; each of the three barrier sites
  (`otlp-raw`, `otlp-sketch-envelope`, `otlp-modified-proto`)
  tallies drops in a `HashMap<agg_id, count>` and calls flush
  at loop exit. One summary debug log per driver per batch.

Also: a new unit test
`record_barrier_drop_advances_atomic_and_prom_counter`
that asserts both sides of the helper's contract (atomic
delta == 7 and Prometheus CounterVec delta == 7 when called
with count=7 on a fresh agg_id label).

738 lib tests pass (+1), clippy clean, fmt clean.

Co-authored-by: Claude Opus 4.7 (1M context) <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.

1 participant