Reconfigurable Senders#
Some actors are constructed before the full messaging graph is available.
For example, the ReconfigurableMailboxSender
is used during MeshAgent::bootstrap
to allow early creation of the Proc
and agent before outbound routing is available.
The .configure(...)
method installs the actual router later, once mesh wiring is complete.
Motivation#
Actors like mesh_agent
are created before remote routing infrastructure is established. These actors need to send messages during setup, but the concrete MailboxSender
they will use hasn’t been determined yet.
To solve this, ReconfigurableMailboxSender
implements [MailboxSender
] and supports deferred configuration: it starts by queueing messages in memory, then later transitions to forwarding once a real sender is available.
Internal Structure#
The sender wraps a state machine:
struct ReconfigurableMailboxSender {
state: Arc<RwLock<ReconfigurableMailboxSenderState>>,
}
There are two possible states:
type Post = (MessageEnvelope, PortHandle<Undeliverable<MessageEnvelope>>);
enum ReconfigurableMailboxSenderState {
Queueing(Mutex<Vec<Post>>),
Configured(BoxedMailboxSender),
}
In the
Queueing
state, messages are buffered.When
.configure(...)
is called, the queue is flushed into the new sender, and the state is replaced withConfigured(...)
.
Configuration#
The .configure(...)
method installs the actual sender. If called while in the Queueing state
, it:
Drains all buffered messages to the given sender
Transitions to the
Configured
stateReturns
true
if this was the first successful configuration
Subsequent calls are ignored and return false
.
fn configure(&self, sender: BoxedMailboxSender) -> bool {
let mut state = self.state.write().unwrap();
if state.is_configured() {
return false;
}
let queued = std::mem::replace(
&mut *state,
ReconfigurableMailboxSenderState::Configured(sender.clone()),
);
for (envelope, return_handle) in queued.into_queueing().unwrap().into_inner().unwrap() {
sender.post(envelope, return_handle);
}
*state = ReconfigurableMailboxSenderState::Configured(sender);
true
}
This guarantees that messages posted before configuration are not dropped - they are delivered in-order once the sender becomes available.