Class: Stoplight::Infrastructure::Redis::Storage::State
- Inherits:
-
Object
- Object
- Stoplight::Infrastructure::Redis::Storage::State
- Includes:
- Domain::_StateStore
- Defined in:
- lib/stoplight/infrastructure/redis/storage/state.rb,
sig/_private/stoplight/infrastructure/redis/storage/state.rbs
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 openedrecovery_scheduled_after: timestamp (float) when recovery probe allowedrecovery_started_at: timestamp (float) when recovery probe began
Instance Attribute Summary collapse
-
#clock ⇒ Domain::_Clock
readonly
Returns the value of attribute clock.
-
#cool_off_time ⇒ timestamp
readonly
Returns the value of attribute cool_off_time.
-
#key_space ⇒ KeySpace
readonly
Returns the value of attribute key_space.
-
#redis ⇒ redis
readonly
Returns the value of attribute redis.
-
#scripting ⇒ Scripting
readonly
Returns the value of attribute scripting.
-
#state_key ⇒ String
readonly
Returns the value of attribute state_key.
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
-
#transition_to_green ⇒ Boolean
Transitions to GREEN state and ensures only one notification.
-
#transition_to_red ⇒ Boolean
Transitions to RED state and ensures only one notification.
-
#transition_to_yellow ⇒ Boolean
Transitions to YELLOW (recovery) state and ensures only one notification.
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 Attribute Details
#clock ⇒ Domain::_Clock (readonly)
Returns the value of attribute clock.
97 98 99 |
# File 'lib/stoplight/infrastructure/redis/storage/state.rb', line 97 def clock @clock end |
#cool_off_time ⇒ timestamp (readonly)
Returns the value of attribute cool_off_time.
98 99 100 |
# File 'lib/stoplight/infrastructure/redis/storage/state.rb', line 98 def cool_off_time @cool_off_time end |
#key_space ⇒ KeySpace (readonly)
Returns the value of attribute key_space.
96 97 98 |
# File 'lib/stoplight/infrastructure/redis/storage/state.rb', line 96 def key_space @key_space end |
#redis ⇒ redis (readonly)
Returns the value of attribute redis.
94 95 96 |
# File 'lib/stoplight/infrastructure/redis/storage/state.rb', line 94 def redis @redis end |
#scripting ⇒ Scripting (readonly)
Returns the value of attribute scripting.
95 96 97 |
# File 'lib/stoplight/infrastructure/redis/storage/state.rb', line 95 def scripting @scripting end |
#state_key ⇒ String (readonly)
Returns the value of attribute state_key.
99 100 101 |
# File 'lib/stoplight/infrastructure/redis/storage/state.rb', line 99 def state_key @state_key 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 |
#transition_to_green ⇒ Boolean
Transitions to GREEN state and ensures only one notification
103 104 105 106 107 108 109 110 |
# File 'lib/stoplight/infrastructure/redis/storage/state.rb', line 103 def transition_to_green became_green = scripting.call( :"state/transition_to_green", args: [clock.current_time.to_f], keys: [state_key] ) became_green == 1 end |
#transition_to_red ⇒ Boolean
Transitions to RED state and ensures only one notification
125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/stoplight/infrastructure/redis/storage/state.rb', line 125 def transition_to_red current_ts = clock.current_time.to_f recovery_scheduled_after_ts = current_ts + cool_off_time became_red = scripting.call( :"state/transition_to_red", args: [current_ts, recovery_scheduled_after_ts], keys: [state_key] ) became_red == 1 end |
#transition_to_yellow ⇒ Boolean
Transitions to YELLOW (recovery) state and ensures only one notification
114 115 116 117 118 119 120 121 |
# File 'lib/stoplight/infrastructure/redis/storage/state.rb', line 114 def transition_to_yellow became_yellow = scripting.call( :"state/transition_to_yellow", args: [clock.current_time.to_f], keys: [state_key] ) became_yellow == 1 end |