Class: BreakerMachines::DSL::CircuitBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/breaker_machines/dsl.rb

Overview

DSL builder for configuring circuit breakers with a fluent interface

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeCircuitBuilder

Returns a new instance of CircuitBuilder.



265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
# File 'lib/breaker_machines/dsl.rb', line 265

def initialize
  @config = {
    failure_threshold: 5,
    failure_window: 60.seconds,
    success_threshold: 1,
    timeout: nil,
    reset_timeout: 60.seconds,
    half_open_calls: 1,
    exceptions: [StandardError],
    storage: nil,
    metrics: nil,
    fallback: nil,
    on_open: nil,
    on_close: nil,
    on_half_open: nil,
    on_reject: nil,
    notifications: [],
    fiber_safe: BreakerMachines.config.fiber_safe
  }
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



263
264
265
# File 'lib/breaker_machines/dsl.rb', line 263

def config
  @config
end

Instance Method Details

#backends(*backend_list) ⇒ Object

Configure multiple backends



396
397
398
# File 'lib/breaker_machines/dsl.rb', line 396

def backends(*backend_list)
  @config[:backends] = backend_list.flatten
end

#fallback(value = nil, &block) ⇒ Object

Raises:

  • (ArgumentError)


355
356
357
358
359
360
361
362
363
364
365
366
367
# File 'lib/breaker_machines/dsl.rb', line 355

def fallback(value = nil, &block)
  raise ArgumentError, 'Fallback requires either a value or a block' if value.nil? && !block_given?

  fallback_value = block || value

  if @config[:fallback].is_a?(Array)
    @config[:fallback] << fallback_value
  elsif @config[:fallback]
    @config[:fallback] = [@config[:fallback], fallback_value]
  else
    @config[:fallback] = fallback_value
  end
end

#fiber_safe(enabled = true) ⇒ Object

rubocop:disable Style/OptionalBooleanParameter



419
420
421
# File 'lib/breaker_machines/dsl.rb', line 419

def fiber_safe(enabled = true) # rubocop:disable Style/OptionalBooleanParameter
  @config[:fiber_safe] = enabled
end

#half_open_requests(count) ⇒ Object



326
327
328
329
# File 'lib/breaker_machines/dsl.rb', line 326

def half_open_requests(count)
  validate_positive_integer!(:half_open_requests, count)
  @config[:half_open_calls] = count
end

#handle(*exceptions) ⇒ Object



415
416
417
# File 'lib/breaker_machines/dsl.rb', line 415

def handle(*exceptions)
  @config[:exceptions] = exceptions
end

#hedgedObject

Configure hedged requests



386
387
388
389
390
391
392
393
# File 'lib/breaker_machines/dsl.rb', line 386

def hedged(&)
  if block_given?
    hedged_builder = HedgedBuilder.new(@config)
    hedged_builder.instance_eval(&)
  else
    @config[:hedged_requests] = true
  end
end

#max_concurrent(limit) ⇒ Object



423
424
425
426
# File 'lib/breaker_machines/dsl.rb', line 423

def max_concurrent(limit)
  validate_positive_integer!(:max_concurrent, limit)
  @config[:max_concurrent] = limit
end

#metrics(recorder = nil, &block) ⇒ Object



351
352
353
# File 'lib/breaker_machines/dsl.rb', line 351

def metrics(recorder = nil, &block)
  @config[:metrics] = recorder || block
end

#notify(service, url = nil, events: %i[open close],, **options) ⇒ Object



405
406
407
408
409
410
411
412
413
# File 'lib/breaker_machines/dsl.rb', line 405

def notify(service, url = nil, events: %i[open close], **options)
  notification = {
    via: service,
    url: url,
    events: Array(events),
    options: options
  }
  @config[:notifications] << notification
end

#on_close(&block) ⇒ Object



373
374
375
# File 'lib/breaker_machines/dsl.rb', line 373

def on_close(&block)
  @config[:on_close] = block
end

#on_half_open(&block) ⇒ Object



377
378
379
# File 'lib/breaker_machines/dsl.rb', line 377

def on_half_open(&block)
  @config[:on_half_open] = block
end

#on_open(&block) ⇒ Object



369
370
371
# File 'lib/breaker_machines/dsl.rb', line 369

def on_open(&block)
  @config[:on_open] = block
end

#on_reject(&block) ⇒ Object



381
382
383
# File 'lib/breaker_machines/dsl.rb', line 381

def on_reject(&block)
  @config[:on_reject] = block
end

#parallel_calls(count, timeout: nil) ⇒ Object

Advanced features



429
430
431
432
# File 'lib/breaker_machines/dsl.rb', line 429

def parallel_calls(count, timeout: nil)
  @config[:parallel_calls] = count
  @config[:parallel_timeout] = timeout
end

#parallel_fallback(fallback_list) ⇒ Object

Configure parallel fallback execution



401
402
403
# File 'lib/breaker_machines/dsl.rb', line 401

def parallel_fallback(fallback_list)
  @config[:fallback] = ParallelFallbackWrapper.new(fallback_list)
end

#reset_after(duration, jitter: nil) ⇒ Object



311
312
313
314
315
316
317
318
319
# File 'lib/breaker_machines/dsl.rb', line 311

def reset_after(duration, jitter: nil)
  validate_positive_integer!(:duration, duration.to_i)
  @config[:reset_timeout] = duration.to_i

  return unless jitter

  validate_jitter!(jitter)
  @config[:reset_timeout_jitter] = jitter
end

#storage(backend, **options) ⇒ Object



331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
# File 'lib/breaker_machines/dsl.rb', line 331

def storage(backend, **options)
  @config[:storage] = case backend
                      when :memory
                        Storage::Memory.new(**options)
                      when :bucket_memory
                        Storage::BucketMemory.new(**options)
                      when :cache
                        Storage::Cache.new(**options)
                      when :null
                        Storage::Null.new(**options)
                      when :fallback_chain
                        config = options.is_a?(Proc) ? options.call(timeout: 5) : options
                        Storage::FallbackChain.new(config)
                      when Class
                        backend.new(**options)
                      else
                        backend
                      end
end

#threshold(failures: nil, failure_rate: nil, minimum_calls: nil, within: 60.seconds, successes: nil) ⇒ Object



286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
# File 'lib/breaker_machines/dsl.rb', line 286

def threshold(failures: nil, failure_rate: nil, minimum_calls: nil, within: 60.seconds, successes: nil)
  if failure_rate
    # Rate-based threshold
    validate_failure_rate!(failure_rate)
    validate_positive_integer!(:minimum_calls, minimum_calls) if minimum_calls

    @config[:failure_rate] = failure_rate
    @config[:minimum_calls] = minimum_calls || 5
    @config[:use_rate_threshold] = true
  elsif failures
    # Absolute count threshold (existing behavior)
    validate_positive_integer!(:failures, failures)
    @config[:failure_threshold] = failures
    @config[:use_rate_threshold] = false
  end

  validate_positive_integer!(:within, within.to_i)
  @config[:failure_window] = within.to_i

  return unless successes

  validate_positive_integer!(:successes, successes)
  @config[:success_threshold] = successes
end

#timeout(duration) ⇒ Object



321
322
323
324
# File 'lib/breaker_machines/dsl.rb', line 321

def timeout(duration)
  validate_non_negative_integer!(:timeout, duration.to_i)
  @config[:timeout] = duration.to_i
end