On this pageFunctions
Command/Interruptible
/**
* Defines an interruptible Command. Like `Command.define`, but every
* invocation registers under a key in the runtime's interrupt registry for
* the duration of its Effect, and the returned Definition carries an
* `Interrupt` constructor that builds the Command to stop it.
*
* Keys are namespaced by the Command name automatically. With no declared
* args the key is the Command name itself. With declared args, `toKey` maps
* them to the part that distinguishes invocations, and the full key becomes
* `` `${name}:${toKey(args)}` ``, so keys never collide across definitions
* and call sites never restate the name. Derive the key part from the Model
* identity that owns the in-flight work (a list item id, an entity id), never
* from a generated value: the update function is pure, and any invocation you
* can meaningfully target is already distinguished by data in the Model.
*
* Semantics:
*
* - A key is an address, not a lock. Any number of invocations may run under
* one key concurrently, and dispatching never interrupts anything.
* Interruption only happens when update returns an Interrupt Command.
* - `Definition.Interrupt` produces a Command whose Effect interrupts every
* current holder of the key and results in `toMessage(outcome)`. The
* outcome is `Interrupted` when at least one holder was stopped (the
* stopped holders' result Messages are guaranteed never to dispatch) or
* `NotFound` when nothing held the key. Name the result Message
* `CompletedCancel<CommandName>`.
* - To dispatch a replacement after cancelling, sequence through the
* Interrupt's result Message: return the new Command from the
* `CompletedCancel<CommandName>` handler. Commands in one batch run
* concurrently with no execution-order guarantee, so `[Interrupt, Next]`
* in a single list is a race, not a sequence.
*
* For work that should stop when the Model says so, reach for a Subscription
* or ManagedResource instead; interruption is for one-shot async work that is
* structurally a Command (for example an in-flight HTTP request, a file read,
* or an upload).
*/
<Name extends string, Results extends readonly Array<Top>>(
name: Name,
results: Results
): (effect: Eff) => DefinitionNoArgs<Name, Eff>
<Name extends string, Fields extends Fields, KeyArgs extends Partial<View<Fields, "Type", TypeOptionalKeys<Fields>, TypeMutableKeys<Fields>>>, Results extends readonly Array<Top>>(
name: Name,
args: Fields,
toKey: (keyArgs: KeyArgs) => string,
results: Results
): (effectBuilder: (args: View<Fields>) => Eff) => DefinitionWithArgs<Name, Fields, KeyArgs, Eff>/**
* An interruptible Command definition with no declared args; its key is the
* Command name. Call as `Definition()` to produce a Command instance; use
* `Definition.Interrupt` to build the Command that stops it.
*/
interface DefinitionNoArgs {
[CommandDefinitionTypeId]: typeof CommandDefinitionTypeId
Interrupt: InterruptDefinitionNoArgs<Name>
name: Name
}/**
* An interruptible Command definition with declared args and a key derived
* from them, namespaced by the Command name. Call as `Definition(args)` to
* produce a Command instance; use `Definition.Interrupt` to build the
* Command that stops every holder of a specific key.
*/
interface DefinitionWithArgs {
[CommandDefinitionTypeId]: typeof CommandDefinitionTypeId
Interrupt: InterruptDefinitionWithArgs<Name, KeyArgs>
name: Name
}/**
* An Interrupt Command definition derived from an interruptible Command
* definition with no declared args. Call as `Definition.Interrupt(toMessage)`
* to produce a Command that interrupts every holder of the definition's key.
*/
interface InterruptDefinitionNoArgs {
[CommandDefinitionTypeId]: typeof CommandDefinitionTypeId
name: `${Name}.Interrupt`
}/**
* An Interrupt Command definition derived from an interruptible Command
* definition with declared args. Call as
* `Definition.Interrupt(keyArgs, toMessage)` to produce a Command that
* interrupts every holder of the key derived from `keyArgs`.
*/
interface InterruptDefinitionWithArgs {
[CommandDefinitionTypeId]: typeof CommandDefinitionTypeId
name: `${Name}.Interrupt`
}/**
* At least one in-flight Command held the interrupt key, and every holder
* has been stopped. Their declared result Messages are guaranteed never to
* dispatch.
*/
const Interrupted: CallableTaggedStruct<"Interrupted", {}>/**
* No Command holds the interrupt key: every target already completed (its
* result Message dispatched or will dispatch) or was never dispatched. The
* two cases are indistinguishable by design.
*/
const NotFound: CallableTaggedStruct<"NotFound", {}>