Skip to content

ActiveRecord State store #815

Description

@bolshakov

Background

A light's state is its operational status independent of raw metrics: whether an operator has locked it to a color, plus the timestamps of its green/yellow/red transitions. Because several processes share one data store, transitions must be first-writer-wins: when a light trips, exactly one process should "win" the transition and send the notification, even though many processes observe the failure at once. The Redis store gets this from an atomic set-if-absent; this ticket reproduces the same guarantee with portable ActiveRecord.

Each backend implements the domain state-store port (snapshot, set-state, transition-to-color, clear) by duck typing. The Redis and Memory state stores are the reference implementations to mirror. The epic describes the schema and how a light's id is derived.

Goal

Implement the ActiveRecord State store conforming to the domain state-store port, with the same first-writer-wins transition semantics Redis provides.

What to do

  • Add the stoplight_states migration to the engine (columns and unique index per the epic schema).
  • Implement snapshot, set-state, and clear as single-row read, upsert, and delete.
  • Implement each transition_to_color so its return value reports whether the caller was the first writer: ensure the row exists without pre-setting the transition marker column, then run a guarded update whose affected-row count is the boolean. transition_to_red refreshes the scheduling fields (and clears the recovery markers) for every writer while detecting the first writer on the breach marker, matching Redis field for field.
  • Timestamps come from the injected clock.
  • Add the store's operations to the benchmark harness.

Acceptance criteria

  • The shared data-store contract examples for set-state and transition-to-color pass against the ActiveRecord State store on SQLite and on Postgres.
  • A spec running two threads that race transition_to_color against Postgres shows exactly one true.
  • A spec shows transition_to_red refreshes the scheduling/recovery fields even for a non-first writer, matching the Redis store's observable result.
  • The benchmark harness includes the State store; 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