Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feature: close commandstats AC gaps (snapshot endpoint, absolute totals, 60s)#113

Merged
KIvanow merged 5 commits into
masterfrom
feature/commandstats-ac-compliance
Apr 21, 2026
Merged

feature: close commandstats AC gaps (snapshot endpoint, absolute totals, 60s)#113
KIvanow merged 5 commits into
masterfrom
feature/commandstats-ac-compliance

Conversation

@jamby77

@jamby77 jamby77 commented Apr 20, 2026

Copy link
Copy Markdown
Collaborator

Stacked on top of #111 to close the remaining acceptance-criteria gaps on project item Add commandstats section to INFO polling (175677003).

Summary

  • Parser: extracts usec_per_call, rejected_calls, failed_calls in addition to calls / usec.
  • Storage: StoredCommandStatsSample gains callsTotal, usecTotal, usecPerCall, rejectedCalls, failedCalls alongside the existing per-poll deltas. SQLite + Postgres get idempotent ADD COLUMN IF NOT EXISTS / addColumnIfMissing migrations; memory adapter picks up the new fields via the shared type.
  • New endpoint: GET /metrics/commandstats returns the current absolute snapshot per command (sourced from the poller's in-memory baseline so we don't round-trip through storage for the hot path).
  • Interval: 15s → 60s, matching MemoryAnalyticsService per the AC.

AC coverage vs item 175677003

AC Status
Polled on dedicated interval (default 60s matching MemoryAnalyticsService)
All cmdstat_ft.* parsed and stored (not just FT.SEARCH) ✅ — implementation is broader (all cmdstat_*)
callsDelta correct; counter-reset detection re-baselines ✅ (unchanged from #111)
usec_per_call stored as average latency in microseconds ✅ (new column)
GET /metrics/commandstats current snapshot ✅ (new)
Persisted with connection_id + timestamp ✅ (unchanged from #111)
Empty-instance returns empty, not an error
Gated on hasVectorSearch ⚠️ Deliberately not gated — see below

hasVectorSearch gating — why this PR does not add it

The AC reasoned "no point polling commandstats for FT.* if the module is not loaded." That reasoning assumes the poller only captures cmdstat_ft.*. The actual implementation captures every cmdstat_* line because the data is useful for any command on any instance (standard GET/SET/HGETALL workloads too). Adding the gate would drop that data for non-Search connections with no upside. Flagging explicitly so reviewers can push back if they'd rather be strict.

Test plan

  • pnpm exec jest src/metrics src/storage/adapters/__tests__/commandstats-samples.spec.ts — 36 pass
  • Parser spec covers all five extracted fields and default-zero behavior
  • Poller spec covers absolute-total persistence and the new getSnapshot() method
  • Controller spec covers the snapshot endpoint + default-connection fallback
  • Adapter round-trip spec covers the new callsTotal, usecTotal, usecPerCall, rejectedCalls, failedCalls fields
  • Full suite: 1046 pass (1 pre-existing proprietary/licenses failure, unrelated)

Note

Medium Risk
Adds a new public metrics endpoint and expands persisted commandstats schema (SQLite/Postgres) with new columns, which carries migration and compatibility risk for existing deployments. Changes polling interval and data shapes (object→array) could impact downstream consumers if any relied on prior formats.

Overview
Closes commandstats acceptance-criteria gaps by capturing and persisting full cmdstat fields (adds callsTotal, usecTotal, usecPerCall, rejectedCalls, failedCalls alongside existing deltas) and updating storage adapters/queries plus idempotent DB migrations for SQLite/Postgres.

Adds a new GET /metrics/commandstats endpoint that serves the latest in-memory snapshot from the poller (no storage round-trip), and updates the commandstats poller to run at 60s intervals while persisting batches that include both absolute totals and deltas.

Introduces a shared InfoParser.parseKvLine() helper (with tests) and reuses it across commandstats parsing, CLIENT LIST parsing, and keyspace parsing in Prometheus metrics.

Reviewed by Cursor Bugbot for commit 702f6ea. Bugbot is set up for automated code reviews on this repo. Configure here.

@jamby77 jamby77 requested a review from KIvanow April 20, 2026 06:35
@jamby77

jamby77 commented Apr 20, 2026

Copy link
Copy Markdown
Collaborator Author

@BugBot review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 1c32423. Configure here.

Base automatically changed from feature/vector-and-commandstats-backend to master April 21, 2026 11:30
@KIvanow

KIvanow commented Apr 21, 2026

Copy link
Copy Markdown
Member

@jamby77 changes look good! Please resolve the conflicts and squash merge it

jamby77 added 5 commits April 21, 2026 19:10
- Parse INFO commandstats section into per-command calls/usec samples
- CommandstatsPollerService polls every 15s, establishes a baseline
  on the first poll, persists deltas thereafter, and re-baselines on
  counter reset (current < previous)
- New command_stats_samples table + saveCommandStatsSamples /
  getCommandStatsHistory / pruneOldCommandStatsSamples on StoragePort
  with SQLite, Postgres, and Memory adapter implementations
- GET /metrics/commandstats/:command/history returns delta samples
  within a time window; client-side derives ops/sec and avg latency
Matches the convention used by the other specs in the metrics module
(slowlog-analyzer, commandstats-poller.service, commandstats.controller).
…als, 60s interval

Covers the remaining acceptance criteria on project item
"Add commandstats section to INFO polling" (175677003):

- Parser now also extracts usec_per_call, rejected_calls, failed_calls
  from each cmdstat line
- StoredCommandStatsSample gains callsTotal, usecTotal, usecPerCall,
  rejectedCalls, failedCalls; persisted alongside the existing per-poll
  deltas across sqlite, postgres, and memory adapters with idempotent
  ALTER migrations
- New GET /metrics/commandstats endpoint returns the current absolute
  snapshot sourced from the poller's in-memory baseline
- Poll interval moved to 60s to match MemoryAnalyticsService per spec

Not gated on hasVectorSearch: the parser captures every cmdstat_* line,
not just FT.*, so the data is useful on instances without the Search
module and the AC's rationale ("no point polling if module not loaded")
does not apply to the actual implementation.
The pattern `split(separator) → split('=') → coerce` appeared inline in
three places:

- commandstats parser (`cmdstat_* ` values, comma-separated)
- Prometheus keyspace gauge update (`db0` values, comma-separated)
- CLIENT LIST parser (`id=1 addr=... name=...`, space-separated)

Consolidate into a single static helper on InfoParser that returns a
Record<string, string>, with callers handling field-specific coercion.
The helper splits on the first `=` only, so values containing `=` are
preserved — fixes a latent edge case in the CLIENT LIST parser where
`pair.split('=')` destructuring dropped trailing segments.

Also changes parseCommandStatsSection to return
CommandStatsSample[] with a `command` field embedded in each sample,
matching the shape of StoredCommandStatsSample and
CommandStatsSnapshotEntry. Consumers iterate the array directly instead
of calling Object.entries.

Also drops an unused SlotStatsMetric import in metrics.parser.ts
surfaced by ESLint.
@jamby77 jamby77 force-pushed the feature/commandstats-ac-compliance branch from 1c32423 to 702f6ea Compare April 21, 2026 16:12
@KIvanow KIvanow merged commit 38ca970 into master Apr 21, 2026
3 checks passed
@KIvanow KIvanow deleted the feature/commandstats-ac-compliance branch April 21, 2026 17:00
@github-actions github-actions Bot locked and limited conversation to collaborators Apr 21, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants