feature: close commandstats AC gaps (snapshot endpoint, absolute totals, 60s)#113
Merged
Conversation
Collaborator
Author
|
@BugBot review |
There was a problem hiding this comment.
✅ 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.
5 tasks
Base automatically changed from
feature/vector-and-commandstats-backend
to
master
April 21, 2026 11:30
Member
|
@jamby77 changes look good! Please resolve the conflicts and squash merge it |
KIvanow
approved these changes
Apr 21, 2026
- 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.
1c32423 to
702f6ea
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on top of #111 to close the remaining acceptance-criteria gaps on project item Add commandstats section to INFO polling (175677003).
Summary
usec_per_call,rejected_calls,failed_callsin addition tocalls/usec.StoredCommandStatsSamplegainscallsTotal,usecTotal,usecPerCall,rejectedCalls,failedCallsalongside the existing per-poll deltas. SQLite + Postgres get idempotentADD COLUMN IF NOT EXISTS/addColumnIfMissingmigrations; memory adapter picks up the new fields via the shared type.GET /metrics/commandstatsreturns 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).MemoryAnalyticsServiceper the AC.AC coverage vs item 175677003
cmdstat_ft.*parsed and stored (not just FT.SEARCH)cmdstat_*)callsDeltacorrect; counter-reset detection re-baselinesusec_per_callstored as average latency in microsecondsGET /metrics/commandstatscurrent snapshotconnection_id+timestamphasVectorSearchhasVectorSearch 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 everycmdstat_*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 passgetSnapshot()methodcallsTotal,usecTotal,usecPerCall,rejectedCalls,failedCallsfieldsproprietary/licensesfailure, 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,failedCallsalongside existing deltas) and updating storage adapters/queries plus idempotent DB migrations for SQLite/Postgres.Adds a new
GET /metrics/commandstatsendpoint 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 LISTparsing, 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.