Arcana::Dispatcher
Runs a service's requests concurrently: each in its own fiber, at most
max_concurrent at once (nil for no cap), and reports busy while at
least one request is in flight. Toolset and Service use one each.
Before this, a service took one request at a time, so its throughput was 1 / handler latency however much its backend could take: a handler that spends 3 s on a provider call served 20 requests a minute.
Two ways in:
submitwaits for a free slot before starting the fiber. A mailbox reader uses it, so it stops taking messages while every slot is busy and the rest wait in the (bounded) mailbox.submit_nowaitstarts the fiber at once and lets it wait for a slot there. A WebSocket read loop uses it: the loop must keep reading, because it also carries the replies to requests a handler may be waiting on.
Lanes split the work by backend. Each lane can have its own cap
(limit_lane), and a request first waits for a slot in its lane, then
for one of the dispatcher's. Waiting for a lane holds no dispatcher
slot, so a backed-up lane doesn't crowd out requests for the others.
Constants
A cap protects the backend a handler calls: most are HTTP APIs with rate limits (Runware, for one, recommends 2–4 concurrent requests).
Constructors
Instance methods
Cap a lane: its requests run at most max_concurrent at once. A lane
without a cap is limited only by the dispatcher's own.