@startuml Actor Lifecycle
title Actor Lifecycle Management
participant "spawn()" as Spawn
participant "ActorRef<T>" as ActorRef
participant "JoinHandle" as JoinHandle
participant "run_actor_lifecycle()" as Lifecycle
participant "Actor::on_start()" as OnStart
participant "Actor::on_run()" as OnRun
participant "Actor::on_stop()" as OnStop
== Initialization Phase ==
Spawn -> Lifecycle: Start actor task
activate Lifecycle
Lifecycle -> OnStart: Call on_start(args, &actor_ref)
activate OnStart
alt Successful Initialization
OnStart --> Lifecycle: Ok(actor_instance)
deactivate OnStart
note right of Lifecycle: Actor instance created successfully
Lifecycle -> Lifecycle: Store actor instance
Lifecycle -> Lifecycle: Create ActorWeak reference
Lifecycle -> Lifecycle: Enter main processing loop
else Initialization Failure
OnStart --> Lifecycle: Err(error)
deactivate OnStart
Lifecycle --> JoinHandle: ActorResult::Failed { phase: OnStart, actor: None, error, killed: false }
deactivate Lifecycle
note right of JoinHandle: Actor never started - no instance available
end
== Processing Phase ==
loop Main Actor Loop
Lifecycle -> Lifecycle: tokio::select! (biased)
alt Termination Signal (Highest Priority)
Lifecycle -> Lifecycle: Received ControlSignal::Terminate
note right of Lifecycle: Kill signal has highest priority
Lifecycle -> OnStop: Call on_stop(&actor_weak, killed = true)
else Graceful Stop Message
Lifecycle -> Lifecycle: Received StopGracefully message
Lifecycle -> OnStop: Call on_stop(&actor_weak, killed = false)
else Mailbox Closed
Lifecycle -> Lifecycle: All ActorRef instances dropped
Lifecycle -> OnStop: Call on_stop(&actor_weak, killed = false)
else Message Received
Lifecycle -> Lifecycle: Process incoming message
note right of Lifecycle: Handle message via MessageHandler trait
else on_run Execution (Idle Handler)
Lifecycle -> OnRun: Call actor.on_run(&actor_weak)
activate OnRun
alt on_run Continue
OnRun --> Lifecycle: Ok(true)
deactivate OnRun
note right of Lifecycle: Continue calling on_run when idle
else on_run Disable
OnRun --> Lifecycle: Ok(false)
deactivate OnRun
note right of Lifecycle: Disable idle processing, only handle messages
else on_run Failure
OnRun --> Lifecycle: Err(error)
deactivate OnRun
note right of Lifecycle
Actor terminates due to runtime error.
on_stop IS called for cleanup.
end note
Lifecycle -> OnStop: Call on_stop(&actor_weak, killed)
Lifecycle --> JoinHandle: ActorResult::Failed { phase: OnRun, actor: Some(actor), error, killed }
end
end
end
== Termination Phase ==
note over Lifecycle, OnStop
on_stop is called for:
- explicit stop/kill requests
- when all ActorRef instances are dropped
- when on_run returns an error (for cleanup)
end note
activate OnStop
alt on_stop Success
OnStop --> Lifecycle: Ok(())
deactivate OnStop
Lifecycle --> JoinHandle: ActorResult::Completed { actor, killed: false/true }
else on_stop Failure
OnStop --> Lifecycle: Err(stop_error)
deactivate OnStop
Lifecycle --> JoinHandle: ActorResult::Failed { phase: OnStop, actor: Some(actor), error: stop_error, killed }
end
deactivate Lifecycle
== Result Handling ==
JoinHandle -> JoinHandle: await join_handle
activate JoinHandle
alt ActorResult::Completed
note right of JoinHandle
Actor completed successfully
- Final actor state available
- killed flag indicates termination type
end note
else ActorResult::Failed
note right of JoinHandle
Actor failed during lifecycle
- phase indicates where failure occurred
- error contains failure details
- actor state may be available for recovery
end note
end
deactivate JoinHandle
== Lifecycle Method Characteristics ==
note over OnStart
on_start():
✅ Required implementation
✅ Creates actor instance
✅ Can perform async initialization
✅ Failure prevents actor creation
✅ Receives ActorRef for self-reference
end note
note over OnRun
on_run() - Idle Handler:
✅ Optional (default returns Ok(false))
✅ Called when message queue is empty
✅ Messages have priority over on_run
✅ Ok(true) continues idle processing
✅ Ok(false) disables idle processing
✅ Err() terminates actor (on_stop called)
✅ Receives ActorWeak to avoid cycles
end note
note over OnStop
on_stop():
✅ Optional (has default implementation)
✅ Called before actor terminates
✅ killed flag indicates termination type
✅ Can perform cleanup operations
✅ Failure affects final ActorResult
✅ Receives ActorWeak reference
end note
@enduml