Count trigger versus cap
max either ends the wait when the container fills or only limits how much it can hold. One flag, resolveAtMax, picks which.
The situation
Some bins ship the moment they are full. Others hold at most twelve bags but ship on a schedule, and the thirteenth bag must be refused rather than starting a shipment early.
The recipe
const shipsWhenFull = await conditionalAccumulator<BagV1>(`bin-${binKey}`, { role: 'bin', metadata: { binKey }, accumulate: { max: 12 }, timeout: '4h',});
const capped = await conditionalAccumulator<BagV1>(`dock-${dockKey}`, { role: 'bin', metadata: { binKey: dockKey }, accumulate: { max: 12, resolveAtMax: false, unique: false }, timeout: '4h',});| Dial | Default | Effect |
|---|---|---|
max |
absent (unbounded) | the count trigger |
resolveAtMax |
true |
false makes max a cap: the last slot answers accepted, further adds answer full |
unique |
true |
false lets a repeated key replace its entry in place |
The guarantee
With a cap, an add past max answers 409 full and the row is untouched; the wait still ends by timer or resolve. With unique keys, a repeated key answers 409 duplicate-item, so a scanner double-read is harmless. accumulate_max is a numeric facet, so fill levels are queryable. See Batches and accumulators.
Related patterns
The escalation boundary
Open container
One row is a container that fills over time. Items join one at a time and the workflow wakes once with the ordered collection.
The escalation boundary
A timeout is a delivery window
On a container, the timer closes the window and delivers what it holds. The type has no false branch to handle.
The escalation boundary
Reciprocal add
A bag joins a bin and the bin records the bag in one statement. Both rows change or neither.
