跳转到内容
简体中文

Explain plan

此内容尚不支持你的语言。

“What has this actor been doing?” is a question you ask while an actor is misbehaving. The explain plan answers it: a ring of its most recent message handlings, switched on from the panel — no code change, no restart.

ColumnMeaning
seqPer-actor counter; a gap means the ring wrapped
timeWhen the handler started
messageConstructor name of the message
senderWho sent it, when there was a sender
waitedTime from arrival in the mailbox to handler start
handledTime inside the handler

The dot on each row carries the outcome: green for a clean return, amber for a message the actor stashed, red for a handler that threw (hover for the error).

Pick an actor, set how many messages to keep, press Start recording. The table refreshes once a second while recording. Pressing stop — or leaving the panel, or detaching DevTools — switches the actor back off; a ring left running because a browser tab closed would be a leak nobody asked for.

The same recorder is available on ActorContext, which is the better choice when you already know which actor you care about:

class OrderActor extends Actor<OrderCommand> {
override preStart(): void {
this.context.enableExplainPlan({ capacity: 100 });
}
override onReceive(command: OrderCommand): void {
if (isSuspicious(command)) {
this.log.warn(`recent traffic: ${JSON.stringify(this.context.explainPlan())}`);
}
}
}

explainPlan() returns the entries oldest-first; disableExplainPlan() stops and discards them.

Enabling a plan also starts timestamping that actor’s incoming envelopes — that is what makes the wait figure possible, and why an actor without a plan pays nothing for it.

Two consequences worth knowing:

  • A message that was already queued when you pressed record has no timestamp, so its wait shows as rather than a made-up zero.
  • A stashed message keeps its original timestamp when it is replayed, so its wait spans the whole stash residency. That is the honest answer to “how long did this message wait?”, and it is usually the interesting one — a message that sat in a stash for four seconds did wait four seconds.

One null check per message on actors without a plan. With a plan: a timestamp at enqueue and a fixed-size ring entry per message. The ring never grows past its capacity, and the panel caps a requested capacity at 10 000 — it is a debugging aid, not a log.