pub struct ActrNode<W: Workload> { /* private fields */ }Expand description
Implementations§
Source§impl<W: Workload> ActrNode<W>
impl<W: Workload> ActrNode<W>
Sourcepub fn inproc_mgr(&self) -> Option<Arc<InprocTransportManager>>
pub fn inproc_mgr(&self) -> Option<Arc<InprocTransportManager>>
Sourcepub fn credential_state(&self) -> Option<CredentialState>
pub fn credential_state(&self) -> Option<CredentialState>
Get credential state (if registration has completed)
Sourcepub fn signaling_client(&self) -> Arc<dyn SignalingClient>
pub fn signaling_client(&self) -> Arc<dyn SignalingClient>
Get signaling client (for manual control such as UnregisterRequest)
Sourcepub fn shutdown_token(&self) -> CancellationToken
pub fn shutdown_token(&self) -> CancellationToken
Get shutdown token for this node
Sourcepub async fn discover_route_candidates(
&self,
target_type: &ActrType,
candidate_count: u32,
) -> ActorResult<DiscoveryResult>
pub async fn discover_route_candidates( &self, target_type: &ActrType, candidate_count: u32, ) -> ActorResult<DiscoveryResult>
Discover remote actors of the specified type via signaling server.
This method implements the full runtime compatibility negotiation workflow as specified in the documentation:
§Compatibility Negotiation Flow
-
Step 0: Fast Path (compat.lock.toml)
- Check if
compat.lock.tomlhas a cached negotiation for this service - If found and not expired, use the cached
resolved_fingerprintdirectly
- Check if
-
Step 1: Ideal Path (Exact Match)
- Read the expected fingerprint from
Actr.lock.toml - Request exact match from signaling server
- If found → connection success, system is HEALTHY
- Read the expected fingerprint from
-
Step 2: Trigger Negotiation (Match Failure)
- If no exact match, enter compatibility negotiation mode
-
Step 3: Compatibility Check (Server-side)
- Server performs backward compatibility analysis using proto-sign
-
Step 4: Decision
- Success: Found compatible version → SUB-HEALTHY state
- Update
compat.lock.tomlwith negotiation result - Log warning: “SYSTEM SUB-HEALTHY”
- Update
- Failure: No compatible version → FAILED state
- Log error: “SYSTEM FAILED”
- Success: Found compatible version → SUB-HEALTHY state
§Arguments
target_type: The ActrType of the target service to discovercandidate_count: Maximum number of candidates to return
§Returns
A DiscoveryResult containing candidates and compatibility information
Sourcepub async fn handle_incoming(
&self,
envelope: RpcEnvelope,
caller_id: Option<&ActrId>,
) -> ActorResult<Bytes>
pub async fn handle_incoming( &self, envelope: RpcEnvelope, caller_id: Option<&ActrId>, ) -> ActorResult<Bytes>
Handle incoming message envelope
§Performance Analysis
- create_context: ~10ns
- W::Dispatcher::dispatch: ~5-10ns (static match, can be inlined)
- User business logic: variable
Framework overhead: ~15-20ns (compared to 50-100ns in traditional approaches)
§Zero-cost Abstraction
- Compiler can inline entire call chain
- Match branches can be directly expanded
- Final generated code approaches hand-written match expression
§Parameters
envelope: The RPC envelope containing the messagecaller_id: The ActrId of the caller (from transport layer, None for local Shell calls)
§caller_id Design
Why not in RpcEnvelope?
- Transport layer (WebRTC/Mailbox) already knows the sender
- All connections are direct P2P (no intermediaries)
- Storing in envelope would be redundant duplication
How it works:
- WebRTC/Mailbox stores sender in
MessageRecord.from(Protobuf bytes) - Only decoded when creating Context (once per message)
- Shell calls pass
None(local process, no remote caller) - Remote calls decode from
MessageRecord.from
trace_id vs request_id:
trace_id: Distributed tracing across entire call chain (A → B → C)request_id: Unique identifier for each request-response pair- Both kept for flexibility in complex scenarios
- Single-hop calls: effectively identical
- Multi-hop calls: trace_id spans all hops, request_id per hop
Sourcepub async fn start(self) -> ActorResult<ActrRef<W>>
pub async fn start(self) -> ActorResult<ActrRef<W>>
Start the system
§Startup Sequence
- Connect to signaling server and register Actor
- Initialize transport layer (WebRTC)
- Call lifecycle hook on_start (if Lifecycle trait is implemented)
- Start Mailbox processing loop (State Path serial processing)
- Start Transport (begin receiving messages)
- Create ActrRef for Shell to interact with Workload
§Returns
ActrRef<W>: Lightweight reference for Shell to call Workload methods
Auto Trait Implementations§
impl<W> !Freeze for ActrNode<W>
impl<W> !RefUnwindSafe for ActrNode<W>
impl<W> Send for ActrNode<W>
impl<W> Sync for ActrNode<W>
impl<W> Unpin for ActrNode<W>
impl<W> !UnwindSafe for ActrNode<W>
Blanket Implementations§
Source§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
Source§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
Converts
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
Converts
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more