Coordination
Lanes
One activation per key, under a global concurrency cap.
Quick example
@rivus/agent-kit-collab/lanes exports createLanes. It is an Effect entry and is process-local. It needs effect at the peer version from Installation. It does not take a platform.
Lanes run work per key, one activation at a time, under a global concurrency cap and a bounded queue. The package knows no particular Agent.
import { createLanes } from "@rivus/agent-kit-collab/lanes";
import { Effect } from "effect";
const program = Effect.scoped(
Effect.gen(function* () {
const lanes = yield* createLanes({
maxConcurrent: 4, // activations running at once across all keys
maxQueued: 32, // keys waiting for a free slot
turnTimeoutMs: 600_000, // an activation running longer is interrupted
activate: (key) => runTurn(key), // the work for one key, in a Scope of its own
onExit: (exit) => report(exit) // ActivationSucceeded | ActivationFailed | ActivationInterrupted
});
yield* lanes.wake("room:1"); // "started", "queued" or "coalesced"; never waits for the activation
// ... closing the Scope interrupts the running activations and waits for them.
})
);Scheduling
- A lane runs at most one activation at a time. Every wake that arrives before an activation starts is served by it. Waking a running lane any number of times leaves one activation to follow the running one, and waking a queued lane changes nothing.
- An idle lane starts while a slot is free and nobody waits. Otherwise it waits at the end of the queue, and when
maxQueuedlanes already wait,wakefails withLaneQueueFull. A freed slot goes to the lane that has waited longest, so a lane woken again while it ran waits behind the lanes queued meanwhile. WithoutmaxQueued, the queue holds at most one entry per key. cancel(key)drops the wakes the key owes and interrupts its running activation, and returns once the activation has ended (its finalizers andonExitincluded).closerefuses later wakes withLanesClosed, drops the queue, interrupts every running activation and waits for them. Closing the Scope that created the lanes runs it.- An activation runs with the context
createLanesran in. Its Scope closes when it ends, and the lane moves on only after that. An interrupted activation's finalizers have run before the next activation of any key takes its slot. onExithears how each activation ended. One that succeeded or failed by itself is reported so even when a cancel, close or timeout arrives while its Scope closes.ActivationInterruptedmeans the lanes cut it short, or stopped it before it started, in which caseactivatewas never called.onExitruns uninterruptibly, socancelandclosewait for it. It must not wait for them in turn, and a defect it raises is logged as a warning.
Nothing is persisted. Lanes live in one process.
Failures
Expected failures are typed values with a _tag: LaneQueueFull, LanesClosed and LanesConfigInvalid.
wake returns "started", "queued" or "coalesced" and never waits for the activation. onExit reports ActivationSucceeded, ActivationFailed or ActivationInterrupted.