livery_req_sup (livery v0.2.0)
View SourcePer-request worker registry and concurrency cap.
Adapters call start_request/1 on every inbound request. The worker
is spawned directly in the calling process (so spawning is not
serialized through one process), then this gen_server is told to
monitor it. Workers are temporary: a crashed request does not
restart, the adapter sees the reset and serves the next stream.
In-flight requests are tracked in a lock-free counters array, not
by enumerating processes: start_request/1 reads the count to
enforce max_concurrent_requests (application environment, default
- and answers
{error, overload}past the cap, which the adapter turns into a503. The count is incremented when a worker is admitted and decremented when this server sees the worker'sDOWN, so a worker that iskilled (which skips any in-process cleanup) is still accounted for. This bounds process and memory growth under a request flood. Operators should additionally bound the node with+P/+Qinvm.args(a library cannot impose those downstream); seeconfig/vm.args.example.
The cap is a soft bound: the read-then-increment is not atomic, so a concurrent burst may admit a few past the cap, the same as the previous supervisor-count-based check.
Summary
Functions
Number of requests currently in flight (0 if the app is down).
Spawn a new livery_req_proc worker, unless the in-flight count is at
the max_concurrent_requests cap, in which case return
{error, overload} so the adapter can shed load with a 503.
Types
-type state() :: #state{counter :: counters:counters_ref()}.
Functions
-spec in_flight() -> non_neg_integer().
Number of requests currently in flight (0 if the app is down).
-spec init([]) -> {ok, state()}.
-spec start_request(livery_req_proc:args()) -> {ok, pid()} | {error, term()}.
Spawn a new livery_req_proc worker, unless the in-flight count is at
the max_concurrent_requests cap, in which case return
{error, overload} so the adapter can shed load with a 503.