///|
/// Defines the strategy used by a supervisor when a child actor fails.
pub enum SupervisionStrategy {
/// Restart only the failed child actor.
OneForOne
/// Restart all child actors managed by the supervisor.
OneForAll
/// Restart the failed child actor and any actors started after it.
RestForOne
}
///|
/// A Supervisor manages a set of child actors and applies a supervision strategy upon failure.
pub struct Supervisor {
strategy : SupervisionStrategy
max_retries : Int
}
///|
/// Creates a new Supervisor with the specified strategy and retry limit.
pub fn Supervisor::new(
strategy : SupervisionStrategy,
max_retries : Int,
) -> Supervisor {
{ strategy, max_retries }
}
///|
test "supervisor creation" {
let _s1 = Supervisor::new(OneForOne, 3)
let _s2 = Supervisor::new(OneForAll, 3)
let _s3 = Supervisor::new(RestForOne, 3)
}
///|
priv enum DummyMsg {
Increment
FailOnce
GetState(ActorRef[Int])
}
///|
suberror DummyError derive(Debug)
///|
async fn dummy_behavior(_context : Context, state : Int, msg : DummyMsg) -> Int {
@async.pause()
match msg {
Increment => state + 1
FailOnce => {
if state > 0 {
raise DummyError
}
state
}
GetState(reply_to) => {
reply_to.send(state)
state
}
}
}
///|
async test "supervision one-for-one restart" {
@async.with_task_group(group => {
let system = ActorSystem::new("test_system", group)
let supervisor = Supervisor::new(OneForOne, 3)
let actor = system.spawn(dummy_behavior, 0, supervisor~)
// Create an actor to receive the reply
let reply_box = @aqueue.Queue(kind=@aqueue.Unbounded)
let reply_ref = { id: 99, mailbox: reply_box }
actor.send(Increment) // state becomes 1
actor.send(FailOnce) // state is 1 > 0, raises error -> supervisor restarts actor -> state reset to 0
actor.send(GetState(reply_ref))
@async.sleep(50)
try {
let final_state = reply_box.get()
match final_state {
User(val) =>
if val != 0 {
fail("Expected state to be 0 after restart")
}
_ => fail("Expected User message")
}
} catch {
_ => fail("Failed to get state")
}
})
}