Skip to content

Dynamic Children

ActorMap is a keyed registry of one actor type: same actor shape, many instances, keyed by id. broadcast() sends one event to every child.

const orders = new ActorMap(createOrderWorker);
orders.spawn("ord_1"); // createOrderWorker("ord_1")

Constructor: new ActorMap(factory, options?). Factory receives the key and returns the actor. Every spawn(key) creates a fresh instance.

Not a map of things. The constructor is a factory, the actor to replicate. new ActorMap(shop) means “spawn copies of shop-shaped actors.”

const orders = new ActorMap(
(orderId) =>
new Actor({
inputs: [ship, cancel],
states: [picking, shipped],
initial: picking,
context: { orderId },
setup: (m) => {
m.on(picking, ship, () => ({ state: shipped }));
m.on(picking, cancel, () => ({ state: picking }));
},
}),
);

Same actor, fresh per key. spawn("ord_1") twice, two independent workers.

A child that answers back holds its receiver in context. The map does no wiring:

const orders = new ActorMap(
(orderId) =>
new Actor({
context: { orderId, reportTo: shop },
// ...
}),
);

The child calls context.get().reportTo.send(...) when it has a result.

orders.spawn("ord_1");
orders.ensure("ord_1"); // no-op if exists
orders.send("ord_1", ship.create());
orders.kill("ord_1");
orders.has("ord_1"); // boolean
orders.keys(); // string[]
orders.snapshot("ord_1"); // Snapshot | undefined
const shop = new Actor({
inputs: [checkoutDone, cancelAll],
states: [open],
initial: open,
setup: (m) => {
m.on(open, checkoutDone, (event) => {
orders.ensure(event.payload.orderId);
return {};
});
m.onAny(cancelAll, () => {
broadcast(orders, cancel.create());
return {};
});
},
});

ensure spawns only if missing. No duplicate workers for the same id.

{ autoReap: true } removes a child the moment it completes or dies into __error. No manual cleanup.

const orders = new ActorMap(createOrderWorker, { autoReap: true });
orders.spawn("ord_1"); // size 1
orders.send("ord_1", ship.create()); // worker ships, auto-removed
orders.has("ord_1"); // false

Send an event to all children.

broadcast(orders, cancel.create());

Without sugar: for (const id of orders.keys()) orders.send(id, cancel.create()).

Use ActorMap when children arrive at runtime with unknown count. Use regions when the children are known at construction.