class

Arcana::Dispatcher

Inherits Reference < Object

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:

  • submit waits 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_nowait starts 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

DEFAULT_MAX_CONCURRENT = 8

A cap protects the backend a handler calls: most are HTTP APIs with rate limits (Runware, for one, recommends 2–4 concurrent requests).

Constructors

new(max_concurrent : Int32 | Nil = DEFAULT_MAX_CONCURRENT, on_busy : Proc(Bool, Nil) | Nil = nil)
Source

Instance methods

in_flight

Requests running now.

Source
lanes?

Whether any lane has a cap.

Source
limit_lane(name : String, max_concurrent : Int32) : Nil

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.

Source
max_concurrent
Source
submit

Wait for a free slot, then run job in its own fiber.

Source
submit_nowait(lane : Proc(String | Nil) | Nil = nil, &job : -> ) : Nil

Run job in its own fiber. The fiber works out its lane (lane returns a name, or nil for none), waits for a slot in that lane if it has a cap, then for one of the dispatcher's.

Source