class Backend
Represents a live backend client and its admission state.
Definitions
def initialize(endpoint, client, exchange_limit:, &available)
Initialize a backend.
Signature
-
parameter
endpointEndpoint The endpoint served by this backend.
-
parameter
clientInterface(:call, :close) The HTTP client for the endpoint.
-
parameter
exchange_limitInteger The maximum number of outstanding response exchanges.
-
yields
{|backend| ...} Invoked when the backend can accept another request.
Implementation
def initialize(endpoint, client, exchange_limit:, &available)
raise ArgumentError, "Exchange limit must be positive!" unless exchange_limit.positive?
@endpoint = endpoint
@client = client
@exchange_limit = exchange_limit
@available = available
@guard = Thread::Mutex.new
@active = true
@processing = false
@exchanges = 0
@queued = false
@closed = false
end
attr :endpoint
Signature
-
attribute
Endpoint The endpoint served by this backend.
def name
Signature
-
attribute
String The stable backend name.
Implementation
def name
@endpoint.name
end
attr :exchange_limit
Signature
-
attribute
Integer The maximum number of outstanding response exchanges.
def start
Start advertising this backend as available.
Implementation
def start
notify_available
end
def reserve
Reserve the processing slot and one response exchange.
Signature
-
returns
Boolean Whether the backend was successfully reserved.
Implementation
def reserve
@guard.synchronize do
@queued = false
if @active && !@processing && @exchanges < @exchange_limit
@processing = true
@exchanges += 1
return true
end
end
return false
end
def call(request)
Send a request to the backend.
Signature
-
parameter
requestProtocol::HTTP::Request The upstream request.
-
returns
Protocol::HTTP::Response The upstream response.
Implementation
def call(request)
@client.call(request)
end
def processed
Release the request-processing slot after response headers arrive.
Implementation
def processed
@guard.synchronize do
raise RuntimeError, "Backend is not processing a request!" unless @processing
@processing = false
end
notify_available
end
def failed
Release both reservations when a request fails before response headers.
Implementation
def failed
close = @guard.synchronize do
raise RuntimeError, "Backend is not processing a request!" unless @processing
@processing = false
@exchanges -= 1
should_close?
end
notify_available
close_client if close
end
def release
Release an outstanding response exchange.
Implementation
def release
close = @guard.synchronize do
raise RuntimeError, "Backend has no outstanding exchange!" unless @exchanges.positive?
@exchanges -= 1
should_close?
end
notify_available
close_client if close
end
def retire
Retire this backend without interrupting outstanding responses.
Implementation
def retire
close = @guard.synchronize do
@active = false
should_close?
end
close_client if close
end
def active?
Signature
-
returns
Boolean Whether this backend still accepts new requests.
Implementation
def active?
@guard.synchronize{@active}
end
def exchanges
Signature
-
returns
Integer The number of outstanding response exchanges.
Implementation
def exchanges
@guard.synchronize{@exchanges}
end
def processing?
Signature
-
returns
Boolean Whether a request is waiting for response headers.
Implementation
def processing?
@guard.synchronize{@processing}
end