Zum Inhalt springen
Deutsch

Envelope

Dieser Inhalt ist noch nicht in deiner Sprache verfügbar.

Envelope<T> = object

Defined in: src/internal/Mailbox.ts:6

T = unknown

readonly optional context?: LogContextData

Defined in: src/internal/Mailbox.ts:15

Optional MDC snapshot captured at tell time. Propagated through the actor’s onReceive so log lines emitted while handling this message (and any tells issued from inside it) carry the originating context. See LogContext.


readonly optional enqueuedAtMs?: number

Defined in: src/internal/Mailbox.ts:43

Wall clock at first enqueue, stamped while the receiving actor has an explain plan enabled or the system has metrics enabled — the two consumers of it (ActorContext.enableExplainPlan and actor_mailbox_wait_seconds). Absent otherwise, because a stamp is a clock read on the framework’s hottest path and #411 removed exactly these when nothing reads them.

A stashed message keeps its original stamp when replayed (prependUser does not restamp), so the explain plan’s mailbox wait measures the whole time from arrival to handling — stash residency included, which is what a per-actor debugging view wants beside the stashed outcome that explains it. The metric deliberately reads it differently; see replayed.

Resolution is one millisecond (Date.now()), which is why the wait histogram’s finest bucket is 1 ms rather than something sub-millisecond that the clock could never distinguish.


readonly message: T

Defined in: src/internal/Mailbox.ts:7


readonly optional replayed?: boolean

Defined in: src/internal/Mailbox.ts:63

Set when this envelope re-entered the queue from the stash rather than arriving fresh, so enqueuedAtMs no longer marks the start of its current queue residency.

actor_mailbox_wait_seconds skips these. The aggregate has no labels and no outcome column, so one actor stashing for thirty seconds while it waits on a resource would land a thirty-second observation in the top bucket and drown the queueing signal every other actor contributes — where the explain plan shows the same message beside the stashed entry that accounts for it. Stash residency is application semantics; mailbox wait is meant to be backlog.

The other replay path, ActorCell.prependUserMessages, needs no marker: it builds envelopes with no stamp at all, so it is already excluded. Throttle re-parking is deliberately not marked — a throttled message really is waiting in the queue for an actor that cannot keep up, which is precisely what the metric is asking about.


readonly sender: ActorRef | null

Defined in: src/internal/Mailbox.ts:8


readonly optional trace?: SpanContext

Defined in: src/internal/Mailbox.ts:23

Optional active-span context captured at tell time. If the tracing extension is enabled and the receiver also has it enabled, the receiver’s actor.receive span links back to this one as its parent — producing one coherent trace across actor hops and cluster nodes. See Tracer.


readonly optional undroppable?: boolean

Defined in: src/internal/Mailbox.ts:102

This envelope carries a lifecycle notification the framework generated and cannot send again, so no load-shedding policy may discard it (#729).

Two envelopes take it today, and the test for admitting a third is the property they share, not their subject: the framework built it, the framework sent it once, and nothing on the framework’s side still holds what it would take to send it again. Neither is application traffic, so neither is a message the caller who set the bound was choosing to lose.

The Terminated a death-watch delivers. The watch was installed through context.watch, the framework promised to answer it, and the answer happens once — there is no retry, no sender to back off, and the dying cell has already cleared its watcher set by the time the queue decides. A bounded mailbox that evicted it left the watcher believing a dead actor was alive, with nothing but an actor_mailbox_dropped_total increment to say so.

The websocket-accept a completed HTTP upgrade hands its hub (#717). The wiring layer closed the only reference to a freshly-upgraded socket into the per-connection actor’s factory and returned; there is no timer and no second copy. A bounded hub that evicted it kept a socket nobody would ever attach listeners to — buffering inbound frames with nothing to drain them and holding its maxConnections slot — for the same one increment.

Set by ActorCell.postSignalEnvelope, which is the only door that sets it, and read in three places: Mailbox.removeOldest and Mailbox.removeNewest, so an eviction from either end steps over it; BoundedMailbox.prependUser, so a bound that now applies to the replay path admits it rather than shedding it (#772); and the cell’s throttle gate, so onExcess: 'drop' does not silently consume it either.

It travels with the envelope rather than being remembered by the mailbox because the envelope outlives any one queue position: it survives a stash / unstashAll round trip and a prependUser replay, and both of those hand it back to a bound that would otherwise get a second chance to shed it.