Class: RaceGuard::Configuration
- Inherits:
-
Object
- Object
- RaceGuard::Configuration
- Defined in:
- lib/race_guard/configuration.rb
Overview
Per-process configuration. Mutations are protected by a Mutex.
Constant Summary collapse
- DEFAULT_ENVIRONMENTS =
%i[development test].freeze
- DEFAULT_SEVERITY =
:info
Instance Method Summary collapse
- #active? ⇒ Boolean
- #add_protect_detector(detector) ⇒ Object
- #add_reporter(reporter) ⇒ Object
- #clear_protect_detectors ⇒ Object
- #clear_reporters ⇒ Object
- #current_environment ⇒ Object
-
#db_lock_read_modify_write_models(*klasses) ⇒ Object
Classes (e.g. ActiveRecord models) to audit for read-modify-write patterns (Epic 4.1).
- #db_lock_read_modify_write_tracks?(klass) ⇒ Boolean
- #disable(name) ⇒ Object
- #disable_rule(name) ⇒ Object
-
#distributed_degrade_silently(*args) ⇒ Object
When true, missing store / Redis errors run the block without a lock and omit error reports.
-
#distributed_key_prefix(*args) ⇒ Object
Optional prefix for lock keys;
niluses the default (see Distributed::KeyBuilder). -
#distributed_lock_store(*args) ⇒ Object
— Epic 10: distributed execution guard (Redis-backed lock store) —.
- #distributed_redis_client(*args) ⇒ Object
-
#distributed_reentrancy(*args) ⇒ Object
When
:skip, nesteddistributed_onceon the same thread/key skips the inner block. -
#distributed_skip_behavior(*args) ⇒ Object
Return value when the lock is not acquired:
:nil(Ruby nil),:sentinel(Distributed::SKIPPED), or:raise(Distributed::LockNotAcquiredError). -
#enable(name) ⇒ Object
rubocop:enable Metrics/MethodLength.
- #enable_rule(name) ⇒ Object
- #enabled?(name) ⇒ Boolean
- #enabled_rule?(name) ⇒ Boolean
- #environments(*names) ⇒ Object
-
#initialize ⇒ Configuration
constructor
rubocop:disable Metrics/MethodLength.
- #protect_detectors ⇒ Object
- #remove_protect_detector(detector) ⇒ Object
- #remove_reporter(reporter) ⇒ Object
- #reporters ⇒ Object
- #severity(*args) ⇒ Object
- #severity_for(name) ⇒ Object
-
#shared_state_memo_globs(*patterns) ⇒ Object
Glob patterns (e.g. lib/*/.rb) scanned for @ivar ||= memoization (Epic 6.4).
- #to_h ⇒ Object
- #watch_commit_safety(name, &block) ⇒ Object
Constructor Details
#initialize ⇒ Configuration
rubocop:disable Metrics/MethodLength
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/race_guard/configuration.rb', line 15 def initialize @mutex = Mutex.new @enabled = Set.new @enabled_rules = Set.new @default_severity = DEFAULT_SEVERITY @severities = {} @environments = DEFAULT_ENVIRONMENTS.dup @reporters = [] @protect_detectors = [] @db_lock_read_modify_write_classes = Set.new @shared_state_memo_globs = [] @distributed_lock_store = nil @distributed_redis_client = nil @distributed_skip_behavior = :nil @distributed_reentrancy = :skip @distributed_key_prefix = nil @distributed_degrade_silently = false end |
Instance Method Details
#active? ⇒ Boolean
94 95 96 |
# File 'lib/race_guard/configuration.rb', line 94 def active? @mutex.synchronize { @environments.include?(current_environment) } end |
#add_protect_detector(detector) ⇒ Object
117 118 119 120 |
# File 'lib/race_guard/configuration.rb', line 117 def add_protect_detector(detector) @mutex.synchronize { @protect_detectors << detector } self end |
#add_reporter(reporter) ⇒ Object
98 99 100 101 |
# File 'lib/race_guard/configuration.rb', line 98 def add_reporter(reporter) @mutex.synchronize { @reporters << reporter } self end |
#clear_protect_detectors ⇒ Object
127 128 129 130 |
# File 'lib/race_guard/configuration.rb', line 127 def clear_protect_detectors @mutex.synchronize { @protect_detectors.clear } self end |
#clear_reporters ⇒ Object
108 109 110 111 |
# File 'lib/race_guard/configuration.rb', line 108 def clear_reporters @mutex.synchronize { @reporters.clear } self end |
#current_environment ⇒ Object
242 243 244 245 |
# File 'lib/race_guard/configuration.rb', line 242 def current_environment raw = ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development' raw.downcase.to_sym end |
#db_lock_read_modify_write_models(*klasses) ⇒ Object
Classes (e.g. ActiveRecord models) to audit for read-modify-write patterns (Epic 4.1). Empty by default: no read tracking / write correlation.
149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/race_guard/configuration.rb', line 149 def db_lock_read_modify_write_models(*klasses) if klasses.compact.empty? return @mutex.synchronize do @db_lock_read_modify_write_classes.to_a end end flat = klasses.length == 1 && klasses.first.is_a?(Array) ? klasses.first : klasses @mutex.synchronize { @db_lock_read_modify_write_classes = Set.new(flat.compact) } self end |
#db_lock_read_modify_write_tracks?(klass) ⇒ Boolean
161 162 163 164 165 166 |
# File 'lib/race_guard/configuration.rb', line 161 def db_lock_read_modify_write_tracks?(klass) k = klass return false unless k.is_a?(Class) @mutex.synchronize { @db_lock_read_modify_write_classes.include?(k) } end |
#disable(name) ⇒ Object
41 42 43 44 45 |
# File 'lib/race_guard/configuration.rb', line 41 def disable(name) sym = name.to_sym @mutex.synchronize { @enabled.delete(sym) } self end |
#disable_rule(name) ⇒ Object
62 63 64 65 66 |
# File 'lib/race_guard/configuration.rb', line 62 def disable_rule(name) sym = name.to_sym @mutex.synchronize { @enabled_rules.delete(sym) } self end |
#distributed_degrade_silently(*args) ⇒ Object
When true, missing store / Redis errors run the block without a lock and omit error reports.
230 231 232 233 234 235 236 |
# File 'lib/race_guard/configuration.rb', line 230 def distributed_degrade_silently(*args) return @mutex.synchronize { @distributed_degrade_silently } if args.empty? v = args.first @mutex.synchronize { @distributed_degrade_silently = (v == true) } self end |
#distributed_key_prefix(*args) ⇒ Object
Optional prefix for lock keys; nil uses the default (see Distributed::KeyBuilder).
222 223 224 225 226 227 |
# File 'lib/race_guard/configuration.rb', line 222 def distributed_key_prefix(*args) return @mutex.synchronize { @distributed_key_prefix } if args.empty? @mutex.synchronize { @distributed_key_prefix = args.first } self end |
#distributed_lock_store(*args) ⇒ Object
— Epic 10: distributed execution guard (Redis-backed lock store) —
180 181 182 183 184 185 |
# File 'lib/race_guard/configuration.rb', line 180 def distributed_lock_store(*args) return @mutex.synchronize { @distributed_lock_store } if args.empty? @mutex.synchronize { @distributed_lock_store = args.first } self end |
#distributed_redis_client(*args) ⇒ Object
187 188 189 190 191 192 |
# File 'lib/race_guard/configuration.rb', line 187 def distributed_redis_client(*args) return @mutex.synchronize { @distributed_redis_client } if args.empty? @mutex.synchronize { @distributed_redis_client = args.first } self end |
#distributed_reentrancy(*args) ⇒ Object
When :skip, nested distributed_once on the same thread/key skips the inner block.
209 210 211 212 213 214 215 216 217 218 219 |
# File 'lib/race_guard/configuration.rb', line 209 def distributed_reentrancy(*args) return @mutex.synchronize { @distributed_reentrancy } if args.empty? sym = args.first.to_sym unless sym == :skip raise ArgumentError, "invalid distributed_reentrancy: #{args.first.inspect}" end @mutex.synchronize { @distributed_reentrancy = sym } self end |
#distributed_skip_behavior(*args) ⇒ Object
Return value when the lock is not acquired: :nil (Ruby nil), :sentinel (Distributed::SKIPPED), or :raise (Distributed::LockNotAcquiredError).
196 197 198 199 200 201 202 203 204 205 206 |
# File 'lib/race_guard/configuration.rb', line 196 def distributed_skip_behavior(*args) return @mutex.synchronize { @distributed_skip_behavior } if args.empty? sym = args.first.to_sym unless %i[nil sentinel raise].include?(sym) raise ArgumentError, "invalid distributed_skip_behavior: #{args.first.inspect}" end @mutex.synchronize { @distributed_skip_behavior = sym } self end |
#enable(name) ⇒ Object
rubocop:enable Metrics/MethodLength
35 36 37 38 39 |
# File 'lib/race_guard/configuration.rb', line 35 def enable(name) sym = name.to_sym @mutex.synchronize { @enabled.add(sym) } self end |
#enable_rule(name) ⇒ Object
56 57 58 59 60 |
# File 'lib/race_guard/configuration.rb', line 56 def enable_rule(name) sym = name.to_sym @mutex.synchronize { @enabled_rules.add(sym) } self end |
#enabled?(name) ⇒ Boolean
47 48 49 50 51 52 53 54 |
# File 'lib/race_guard/configuration.rb', line 47 def enabled?(name) sym = name.to_sym @mutex.synchronize do return false unless @environments.include?(current_environment) @enabled.include?(sym) end end |
#enabled_rule?(name) ⇒ Boolean
68 69 70 71 72 73 74 75 |
# File 'lib/race_guard/configuration.rb', line 68 def enabled_rule?(name) sym = name.to_sym @mutex.synchronize do return false unless @environments.include?(current_environment) @enabled_rules.include?(sym) end end |
#environments(*names) ⇒ Object
87 88 89 90 91 92 |
# File 'lib/race_guard/configuration.rb', line 87 def environments(*names) return @mutex.synchronize { @environments.dup } if names.empty? @mutex.synchronize { @environments = names.map(&:to_sym).freeze } self end |
#protect_detectors ⇒ Object
132 133 134 |
# File 'lib/race_guard/configuration.rb', line 132 def protect_detectors @mutex.synchronize { @protect_detectors.dup } end |
#remove_protect_detector(detector) ⇒ Object
122 123 124 125 |
# File 'lib/race_guard/configuration.rb', line 122 def remove_protect_detector(detector) @mutex.synchronize { @protect_detectors.delete(detector) } self end |
#remove_reporter(reporter) ⇒ Object
103 104 105 106 |
# File 'lib/race_guard/configuration.rb', line 103 def remove_reporter(reporter) @mutex.synchronize { @reporters.delete(reporter) } self end |
#reporters ⇒ Object
113 114 115 |
# File 'lib/race_guard/configuration.rb', line 113 def reporters @mutex.synchronize { @reporters.dup } end |
#severity(*args) ⇒ Object
77 78 79 80 |
# File 'lib/race_guard/configuration.rb', line 77 def severity(*args) @mutex.synchronize { apply_severity_args(args) } self end |
#severity_for(name) ⇒ Object
82 83 84 85 |
# File 'lib/race_guard/configuration.rb', line 82 def severity_for(name) sym = name.to_sym @mutex.synchronize { @severities[sym] || @default_severity } end |
#shared_state_memo_globs(*patterns) ⇒ Object
Glob patterns (e.g. lib/*/.rb) scanned for @ivar ||= memoization (Epic 6.4). Empty by default: memo reports are disabled until patterns are set.
170 171 172 173 174 175 176 |
# File 'lib/race_guard/configuration.rb', line 170 def shared_state_memo_globs(*patterns) return @mutex.synchronize { @shared_state_memo_globs.dup } if patterns.empty? flat = patterns.length == 1 && patterns.first.is_a?(Array) ? patterns.first : patterns @mutex.synchronize { @shared_state_memo_globs = flat.compact.map(&:to_s).freeze } self end |
#to_h ⇒ Object
238 239 240 |
# File 'lib/race_guard/configuration.rb', line 238 def to_h @mutex.synchronize { to_h_unsafe } end |
#watch_commit_safety(name, &block) ⇒ Object
136 137 138 139 140 141 142 143 144 145 |
# File 'lib/race_guard/configuration.rb', line 136 def watch_commit_safety(name, &block) raise ArgumentError, 'watch_commit_safety requires a block' unless block sym = name.to_sym @mutex.synchronize do dsl = CommitSafety::WatcherDSL.new(sym) block.call(dsl) end self end |