lib/semian/protected_resource.rb
# frozen_string_literal: true
module Semian
class ProtectedResource
extend Forwardable
def_delegators :@bulkhead, :destroy, :count, :semid, :tickets, :registered_workers
def_delegators :@circuit_breaker,
:reset,
:mark_failed,
:mark_success,
:request_allowed?,
:open?,
:closed?,
:half_open?
attr_reader :bulkhead, :circuit_breaker, :name
attr_accessor :updated_at
def initialize(name, bulkhead, circuit_breaker)
@name = name
@bulkhead = bulkhead
@circuit_breaker = circuit_breaker
@updated_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
end
def destroy
@bulkhead&.destroy
@circuit_breaker&.destroy
end
def acquire(timeout: nil, scope: nil, adapter: nil, resource: nil)
acquire_circuit_breaker(scope, adapter, resource) do
acquire_bulkhead(timeout, scope, adapter) do |_, wait_time|
Semian.notify(:success, self, scope, adapter, wait_time)
yield self
end
end
end
def in_use?
circuit_breaker&.in_use? || bulkhead&.in_use?
end
private
def acquire_circuit_breaker(scope, adapter, resource)
if @circuit_breaker.nil?
yield self
else
@circuit_breaker.acquire(resource) do
yield self
end
end
rescue ::Semian::OpenCircuitError
Semian.notify(:circuit_open, self, scope, adapter)
raise
end
def acquire_bulkhead(timeout, scope, adapter)
if @bulkhead.nil?
yield self, 0
else
@bulkhead.acquire(timeout: timeout) do |wait_time|
yield self, wait_time
end
end
rescue ::Semian::TimeoutError
Semian.notify(:busy, self, scope, adapter)
raise
end
end
end