Class: Stoplight::Infrastructure::Redis::Storage::State
- Inherits:
-
Object
- Object
- Stoplight::Infrastructure::Redis::Storage::State
- Defined in:
- lib/stoplight/infrastructure/redis/storage/state.rb
Overview
Thread safety is guaranteed by Redis’s single-threaded execution model and the use of Lua scripts for atomic multistep operations.
Redis-backed state storage for a single circuit breaker.
Manages circuit breaker state transitions using Redis hashes and Lua scripts for atomic operations. Ensures notification deduplication across distributed processes - when multiple processes detect the same circuit condition, only one will receive true from transition methods.
All state is stored in a single Redis hash with fields:
-
locked_state: forced lock (UNLOCKED, LOCKED_GREEN, LOCKED_RED) -
breached_at: timestamp (float) when circuit opened -
recovery_scheduled_after: timestamp (float) when recovery probe allowed -
recovery_started_at: timestamp (float) when recovery probe began
Instance Method Summary collapse
- #clear ⇒ Object
-
#initialize(clock:, redis:, scripting:, key_space:, cool_off_time:) ⇒ State
constructor
A new instance of State.
- #set_state(state) ⇒ Object
- #state_snapshot ⇒ Object
- #transition_to_color(color) ⇒ Object
Constructor Details
#initialize(clock:, redis:, scripting:, key_space:, cool_off_time:) ⇒ State
Returns a new instance of State.
42 43 44 45 46 47 48 49 50 |
# File 'lib/stoplight/infrastructure/redis/storage/state.rb', line 42 def initialize(clock:, redis:, scripting:, key_space:, cool_off_time:) @redis = redis @scripting = scripting @key_space = key_space @clock = clock @cool_off_time = cool_off_time @state_key = key_space.key(:state) end |
Instance Method Details
#clear ⇒ Object
73 74 75 76 77 |
# File 'lib/stoplight/infrastructure/redis/storage/state.rb', line 73 def clear redis.with do |client| client.del(state_key) end end |
#set_state(state) ⇒ Object
52 53 54 55 56 57 |
# File 'lib/stoplight/infrastructure/redis/storage/state.rb', line 52 def set_state(state) redis.with do |client| client.hset(state_key, "locked_state", state) end state end |
#state_snapshot ⇒ Object
59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/stoplight/infrastructure/redis/storage/state.rb', line 59 def state_snapshot breached_at_raw, locked_state, recovery_scheduled_after_raw, recovery_started_at_raw = redis.with do |client| client.hmget(state_key, :breached_at, :locked_state, :recovery_scheduled_after, :recovery_started_at) end Domain::StateSnapshot.new( breached_at: breached_at_raw && clock.at(breached_at_raw.to_f), locked_state: locked_state || Stoplight::State::UNLOCKED, recovery_scheduled_after: recovery_scheduled_after_raw && clock.at(recovery_scheduled_after_raw.to_f), recovery_started_at: recovery_started_at_raw && clock.at(recovery_started_at_raw.to_f), time: clock.current_time ) end |
#transition_to_color(color) ⇒ Object
79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/stoplight/infrastructure/redis/storage/state.rb', line 79 def transition_to_color(color) case color when Color::GREEN transition_to_green when Color::YELLOW transition_to_yellow when Color::RED transition_to_red else raise ArgumentError, "Invalid color: #{color}" end end |