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
References
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
stoplight_metricsmigration (one row per light and kind, per the epic schema).Acceptance criteria
bundle exec steep checkandbundle exec standardrbpass.References
ports/metrics_store.rbsredis/storage/unbounded_metrics.rb,redis/storage/recovery_metrics.rb, serialization baseredis/storage/metrics.rb; memory:memory/storage/unbounded_metrics.rbdata_store/metrics.rb,recovery_metrics.rb,metrics_snapshot.rb