BoundedMailbox
Defined in: src/mailbox/BoundedMailbox.ts:15
Mailbox with a fixed upper bound on queued user messages. Policy for what happens when a message arrives on a full mailbox is configurable.
Extends
Section titled “Extends”Type Parameters
Section titled “Type Parameters”T = unknown
Constructors
Section titled “Constructors”Constructor
Section titled “Constructor”new BoundedMailbox<
T>(options):BoundedMailbox<T>
Defined in: src/mailbox/BoundedMailbox.ts:19
Parameters
Section titled “Parameters”options
Section titled “options”Returns
Section titled “Returns”BoundedMailbox<T>
Overrides
Section titled “Overrides”DroppingMailbox<T>.constructor
Properties
Section titled “Properties”deadLetterDrops
Section titled “deadLetterDrops”
readonlydeadLetterDrops:boolean
Defined in: src/mailbox/DroppingMailbox.ts:71
See DropReportingMailbox.deadLetterDrops. Fixed at construction because the cell reads it once, when it registers its observer: a switch a running mailbox could flip would mean re-reading it per dropped message, on the path this class exists to keep cheap.
Inherited from
Section titled “Inherited from”DroppingMailbox.deadLetterDrops
droppedCount
Section titled “droppedCount”droppedCount:
number=0
Defined in: src/mailbox/DroppingMailbox.ts:63
Number of messages dropped by the overflow policy — useful for metrics.
Inherited from
Section titled “Inherited from”Accessors
Section titled “Accessors”Get Signature
Section titled “Get Signature”get size():
number
Defined in: src/internal/Mailbox.ts:406
Number of pending user messages.
Returns
Section titled “Returns”number
Inherited from
Section titled “Inherited from”suspended
Section titled “suspended”Get Signature
Section titled “Get Signature”get suspended():
boolean
Defined in: src/internal/Mailbox.ts:237
Returns
Section titled “Returns”boolean
Inherited from
Section titled “Inherited from”Methods
Section titled “Methods”dequeueSystem()
Section titled “dequeueSystem()”dequeueSystem():
Envelope<unknown> |undefined
Defined in: src/internal/Mailbox.ts:395
Returns
Section titled “Returns”Envelope<unknown> | undefined
Inherited from
Section titled “Inherited from”dequeueUser()
Section titled “dequeueUser()”dequeueUser():
Envelope<T> |undefined
Defined in: src/internal/Mailbox.ts:300
Returns
Section titled “Returns”Envelope<T> | undefined
Inherited from
Section titled “Inherited from”drainSystem()
Section titled “drainSystem()”drainSystem():
Envelope<unknown>[]
Defined in: src/internal/Mailbox.ts:424
Returns
Section titled “Returns”Envelope<unknown>[]
Inherited from
Section titled “Inherited from”drainUser()
Section titled “drainUser()”drainUser():
Envelope<T>[]
Defined in: src/internal/Mailbox.ts:420
Drain all user messages; returns them so the caller can forward to dead letters.
Materialises a fresh array rather than handing out the backing store —
a ring is not a dense array, so there is nothing to hand out. The
allocation is real but it is on the termination path, where the caller
(ActorCell) only iterates the result once.
Returns
Section titled “Returns”Envelope<T>[]
Inherited from
Section titled “Inherited from”enqueue()
Section titled “enqueue()”enqueue(
env):void
Defined in: src/mailbox/BoundedMailbox.ts:48
A switch rather than a match, deliberately.
The pattern-matching convention governs dispatch of an incoming message,
event or command; overflow is none of those — it is a configuration
value fixed at construction, and this is the shape the codebase already
uses for a closed string-literal union (see decodeCrdt in
crdt/DistributedData.ts, which documents itself as the reference).
It matters here because of when this branch runs. A matcher plus one
closure per arm was being built for every message that arrived at a full
mailbox — that is, once per shed message, at the exact moment the system
is already past its capacity and least able to afford it (#974).
Exhaustiveness is not lost, only moved: the never assignment below fails
to compile if a fourth policy is added without an arm here.
Parameters
Section titled “Parameters”Envelope<T>
Returns
Section titled “Returns”void
Overrides
Section titled “Overrides”enqueueSignal()
Section titled “enqueueSignal()”enqueueSignal(
env):void
Defined in: src/mailbox/BoundedMailbox.ts:101
A death notification is queued whatever the bound says — see Mailbox.enqueueSignal.
Straight to the base queue, past the capacity check, and that is the whole
override: every one of the three policies destroyed the notification
otherwise, each in its own way (#729). drop-head evicted whatever sat
at the front, drop-new discarded the notification on arrival — the more
likely of the two, since a Terminated arrives late relative to the
flood that filled the queue — and reject was worse than either: it threw
MailboxFullError synchronously on the sender’s stack, and the sender
is the dying cell’s own watcher-notify loop. That throw escaped
finalizeTermination mid-loop, so the remaining watchers went unnotified,
the parent was never told the child had stopped, and terminate() never
settled. reject is also this class’s constructor default, so the
documented withMailbox(() => new BoundedMailbox({ capacity: n })) shape
reached it without naming it.
Parameters
Section titled “Parameters”Envelope<T>
Returns
Section titled “Returns”void
Overrides
Section titled “Overrides”enqueueSystem()
Section titled “enqueueSystem()”enqueueSystem(
env):void
Defined in: src/internal/Mailbox.ts:296
Parameters
Section titled “Parameters”Envelope<unknown>
Returns
Section titled “Returns”void
Inherited from
Section titled “Inherited from”hasMessages()
Section titled “hasMessages()”hasMessages():
boolean
Defined in: src/internal/Mailbox.ts:399
Returns
Section titled “Returns”boolean
Inherited from
Section titled “Inherited from”hasSystemMessages()
Section titled “hasSystemMessages()”hasSystemMessages():
boolean
Defined in: src/internal/Mailbox.ts:403
Returns
Section titled “Returns”boolean
Inherited from
Section titled “Inherited from”DroppingMailbox.hasSystemMessages
hasUserMessages()
Section titled “hasUserMessages()”hasUserMessages():
boolean
Defined in: src/internal/Mailbox.ts:402
Returns
Section titled “Returns”boolean
Inherited from
Section titled “Inherited from”DroppingMailbox.hasUserMessages
observeDrops()
Section titled “observeDrops()”observeDrops(
observer):void
Defined in: src/mailbox/DroppingMailbox.ts:84
See DropReportingMailbox.observeDrops — additive.
Parameters
Section titled “Parameters”observer
Section titled “observer”Returns
Section titled “Returns”void
Inherited from
Section titled “Inherited from”prependUser()
Section titled “prependUser()”prependUser(
envelopes):void
Defined in: src/mailbox/BoundedMailbox.ts:152
A replay meets the bound, the same way an arrival does (#772).
Until this override existed the base prependUser wrote straight to the
queue, so unstashAll() unshifted a whole stash — up to
DEFAULT_STASH_CAPACITY envelopes — past the capacity check, past the
switch above and past the drop accounting. A reject mailbox never
threw, a drop-head / drop-new mailbox never dropped, and
droppedCount / actor_mailbox_dropped_total under-reported by exactly
the batch. The advertised memory ceiling was not one: capacity: 10
could become 1034.
Which end sheds. The policy is unchanged, only the geometry is: an
arrival lands at the tail and drop-head makes room at the head, a
replay lands at the head and so makes room at the tail. Both read as
“admit the arrival, evict a queued message from the far end”, and the
other choice is indefensible here — evicting the head under a prepend
would discard the messages the replay just put back, which is not a bound
but a way of making unstashAll() a no-op.
Which reason is reported. drop-head when a queued message was
evicted, drop-new when the arrival itself was refused — the closed
two-value vocabulary of MailboxDropReason, applied by what actually
happened rather than by which policy is configured. So a
drop-head mailbox does report drop-new for the tail of a batch bigger
than its capacity: once the queue holds nothing droppable, there is no
room to make and the arrival is what goes. That is where this diverges
from enqueue, which admits and overshoots by one in the same situation
— one envelope over a bound is the arrival rate, a whole stash over it is
the defect.
What reject does. It throws MailboxFullError, and it throws
before admitting anything: all-or-nothing, so a caller that catches it
knows the batch is entirely still its own. The throw lands on the
actor’s own stack, inside its unstashAll(), rather than on a remote
sender’s — and that is the closest thing to a sender a replay has. It is
also not a message lost: ActorCell.unstashAll puts the batch back into
the stash before the error travels on, so the envelopes stay parked and
deadLetterStash still sees them if supervision then restarts or stops
the actor. Choosing reject says “refuse, do not lose”, and refusing
the replay of a stash that no longer fits is what that means here.
An Envelope.undroppable envelope is admitted whatever the policy
says and is never counted, exactly as enqueueSignal admits one at
the tail: a Terminated that round-tripped through a stash must not
become droppable on the way back in (#729).
Parameters
Section titled “Parameters”envelopes
Section titled “envelopes”Envelope<T>[]
Returns
Section titled “Returns”void
Overrides
Section titled “Overrides”resume()
Section titled “resume()”resume():
void
Defined in: src/internal/Mailbox.ts:409
Returns
Section titled “Returns”void
Inherited from
Section titled “Inherited from”suspend()
Section titled “suspend()”suspend():
void
Defined in: src/internal/Mailbox.ts:408
Returns
Section titled “Returns”void
