ActrNode

Struct ActrNode 

Source
pub struct ActrNode<W: Workload> { /* private fields */ }
Expand description

ActrNode - ActrSystem + Workload (1:1 composition)

§Generic Parameters

  • W: Workload type

§MessageDispatcher Association

  • Statically associated via W::Dispatcher
  • Does not store Dispatcher instance (not even ZST needed)
  • Dispatch calls entirely through type system

Implementations§

Source§

impl<W: Workload> ActrNode<W>

Source

pub fn inproc_mgr(&self) -> Option<Arc<InprocTransportManager>>

Get Inproc Transport Manager

§Returns
  • Some(Arc<InprocTransportManager>): Initialized manager
  • None: Not yet started (need to call start() first)
§Use Cases
  • Workload internals need to communicate with Shell
  • Create custom LatencyFirst/MediaTrack channels
Source

pub fn actor_id(&self) -> Option<&ActrId>

Get ActorId (if registration has completed)

Source

pub fn credential_state(&self) -> Option<CredentialState>

Get credential state (if registration has completed)

Source

pub fn signaling_client(&self) -> Arc<dyn SignalingClient>

Get signaling client (for manual control such as UnregisterRequest)

Source

pub fn shutdown_token(&self) -> CancellationToken

Get shutdown token for this node

Source

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
  1. Step 0: Fast Path (compat.lock.toml)

    • Check if compat.lock.toml has a cached negotiation for this service
    • If found and not expired, use the cached resolved_fingerprint directly
  2. 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
  3. Step 2: Trigger Negotiation (Match Failure)

    • If no exact match, enter compatibility negotiation mode
  4. Step 3: Compatibility Check (Server-side)

    • Server performs backward compatibility analysis using proto-sign
  5. Step 4: Decision

    • Success: Found compatible version → SUB-HEALTHY state
      • Update compat.lock.toml with negotiation result
      • Log warning: “SYSTEM SUB-HEALTHY”
    • Failure: No compatible version → FAILED state
      • Log error: “SYSTEM FAILED”
§Arguments
  • target_type: The ActrType of the target service to discover
  • candidate_count: Maximum number of candidates to return
§Returns

A DiscoveryResult containing candidates and compatibility information

Source

pub async fn handle_incoming( &self, envelope: RpcEnvelope, caller_id: Option<&ActrId>, ) -> ActorResult<Bytes>

Handle incoming message envelope

§Performance Analysis
  1. create_context: ~10ns
  2. W::Dispatcher::dispatch: ~5-10ns (static match, can be inlined)
  3. 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 message
  • caller_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
Source

pub async fn start(self) -> ActorResult<ActrRef<W>>

Start the system

§Startup Sequence
  1. Connect to signaling server and register Actor
  2. Initialize transport layer (WebRTC)
  3. Call lifecycle hook on_start (if Lifecycle trait is implemented)
  4. Start Mailbox processing loop (State Path serial processing)
  5. Start Transport (begin receiving messages)
  6. 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<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<'a, T, E> AsTaggedExplicit<'a, E> for T
where T: 'a,

Source§

fn explicit(self, class: Class, tag: u32) -> TaggedParser<'a, Explicit, Self, E>

Source§

impl<'a, T, E> AsTaggedImplicit<'a, E> for T
where T: 'a,

Source§

fn implicit( self, class: Class, constructed: bool, tag: u32, ) -> TaggedParser<'a, Implicit, Self, E>

Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

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
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more