Skip to content

ActiveRecord unbounded + recovery metrics stores #816

Description

@bolshakov

Background

Stoplight decides when to trip by counting outcomes. When a light has no window configured, its metrics are running totals: consecutive successes/failures, the last error, and last-success/last-failure timestamps. The same store, keyed by a different "kind", also tracks the outcomes of recovery probes while a light is healing (recovery metrics). Because writes can arrive out of order across processes, updates are guarded so a delayed write never overwrites a newer value. The Redis store does this with timestamp-guarded field writes; this ticket reproduces it with a locked read-modify-write.

Both stores implement the domain metrics-store port (snapshot, record-success, record-failure, clear). The Redis metrics stores are the reference to mirror, including how a failure is serialized to and from the domain failure object. The epic describes the schema.

Goal

Implement the ActiveRecord unbounded metrics and recovery metrics stores conforming to the domain metrics-store port, with the same out-of-order-write guards Redis has.

What to do

  • Add the stoplight_metrics migration (one row per light and kind, per the epic schema).
  • Implement record-success and record-failure as a transaction that ensures the row exists then reads-modifies-writes under a row lock, replicating the newer-timestamp guards. Record-failure returns the post-write snapshot.
  • Implement the recovery-metrics store as the same behavior keyed by its own kind.
  • Give rows a retention timestamp refreshed on write; expired rows are invisible to snapshots.
  • Reuse the exception-serialization approach used by the existing metrics stores.
  • Add both stores to the benchmark harness.

Acceptance criteria

  • The metrics contract shared examples pass for both the unbounded and recovery metrics ActiveRecord stores, on SQLite and Postgres.
  • A spec writing an older-timestamped update after a newer one shows the newer last-success/last-error is not regressed, matching the Redis store.
  • A spec shows a row past its retention horizon is not reflected in the metrics snapshot.
  • Both stores appear in the benchmark harness; Memory / Redis / ActiveRecord numbers are recorded in the PR description.
  • bundle exec steep check and bundle exec standardrb pass.

References

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions