class Expeditor::Service
Attributes
executor[R]
fallback_enabled[RW]
Public Class Methods
new(opts = {})
click to toggle source
# File lib/expeditor/service.rb, line 8 def initialize(opts = {}) @mutex = Mutex.new @executor = opts.fetch(:executor) { Concurrent::ThreadPoolExecutor.new } @threshold = opts.fetch(:threshold, 0.5) @non_break_count = opts.fetch(:non_break_count, 20) @sleep = opts.fetch(:sleep, 1) granularity = 10 @rolling_number_opts = { size: granularity, per_time: opts.fetch(:period, 10).to_f / granularity } reset_status! @fallback_enabled = true end
Public Instance Methods
break()
click to toggle source
# File lib/expeditor/service.rb, line 39 def break @rolling_number.increment :break end
breaking?()
click to toggle source
# File lib/expeditor/service.rb, line 51 def breaking? @breaking end
current_status()
click to toggle source
@deprecated Use `#status` instead.
# File lib/expeditor/service.rb, line 104 def current_status warn 'Expeditor::Service#current_status is deprecated. Please use #status instead.' @rolling_number.current end
dependency()
click to toggle source
# File lib/expeditor/service.rb, line 43 def dependency @rolling_number.increment :dependency end
failure()
click to toggle source
# File lib/expeditor/service.rb, line 27 def failure @rolling_number.increment :failure end
fallback_enabled?()
click to toggle source
# File lib/expeditor/service.rb, line 47 def fallback_enabled? !!fallback_enabled end
rejection()
click to toggle source
# File lib/expeditor/service.rb, line 31 def rejection @rolling_number.increment :rejection end
reset_status!()
click to toggle source
# File lib/expeditor/service.rb, line 109 def reset_status! @mutex.synchronize do @rolling_number = Expeditor::RollingNumber.new(@rolling_number_opts) @breaking = false @break_start = nil end end
run_if_allowed() { || ... }
click to toggle source
Run given block when the request is allowed, otherwise raise Expeditor::CircuitBreakError. When breaking and sleep time was passed, the circuit breaker tries to close the circuit. So subsequent single command execution is allowed (will not be breaked) to check the service is healthy or not. The circuit breaker only allows one request so other subsequent requests will be aborted with CircuitBreakError. When the test request succeeds, the circuit breaker resets the service status and closes the circuit.
# File lib/expeditor/service.rb, line 63 def run_if_allowed if @breaking now = Time.now # Only one thread can be allowed to execute single request when half-opened. allow_single_request = false @mutex.synchronize do allow_single_request = now - @break_start > @sleep @break_start = now if allow_single_request end if allow_single_request result = yield # This can be raise exception. # The execution succeed, then reset_status! result else raise CircuitBreakError end else open = calc_open if open change_state(true, Time.now) raise CircuitBreakError else yield end end end
shutdown()
click to toggle source
shutdown thread pool after shutdown, if you create thread, RejectedExecutionError is raised.
# File lib/expeditor/service.rb, line 95 def shutdown @executor.shutdown end
status()
click to toggle source
# File lib/expeditor/service.rb, line 99 def status @rolling_number.total end
success()
click to toggle source
# File lib/expeditor/service.rb, line 23 def success @rolling_number.increment :success end
timeout()
click to toggle source
# File lib/expeditor/service.rb, line 35 def timeout @rolling_number.increment :timeout end
Private Instance Methods
calc_open()
click to toggle source
# File lib/expeditor/service.rb, line 119 def calc_open s = @rolling_number.total total_count = s.success + s.failure + s.timeout if total_count >= [@non_break_count, 1].max failure_count = s.failure + s.timeout failure_count.to_f / total_count.to_f >= @threshold else false end end
change_state(breaking, break_start)
click to toggle source
# File lib/expeditor/service.rb, line 130 def change_state(breaking, break_start) @mutex.synchronize do @breaking = breaking @break_start = break_start end end