Supervising Actors
Actors can supervise other actors, if we define an actor loop that fails on a given message
let err = (fun (actor:IActor<string>) -> let rec loop() = async { let! (msg,_) = actor.Receive() if msg <> "fail" then printfn "%s" msg else failwithf "ERRRROROROR" return! loop() } loop() )
then a supervisor will allow the actor to restart or terminate depending on the particular strategy that is in place
Strategies
A supervisor strategy allows you to define the restart semantics for the actors it is watching
OneForOne
A supervisor will only restart the actor that has errored
let oneforone = Supervisor.spawn <| Supervisor.Options.Create(actorOptions = Actor.Options.Create("OneForOne")) |> Supervisor.superviseAll [Actor.spawn (Actor.Options.Create("err_0")) err] !!"err_0" <-- "fail" // This yields Restarting (OneForOne: actor://main-pc/err_0) due to error System.Exception: ERRRROROROR at FSI_0012.err@134-2.Invoke(String message) in D:\Appdev\fsharp.actor\samples\Actor.fsx:line 134 at Microsoft.FSharp.Core.PrintfImpl.go@523-3[b,c,d](String fmt, Int32 len, FSharpFunc`2 outputChar, FSharpFunc`2 outa, b os, FSharpFunc`2 finalize, FSharpList`1 args, Int32 i) at Microsoft.FSharp.Core.PrintfImpl.run@521[b,c,d](FSharpFunc`2 initialize, String fmt, Int32 len, FSharpList`1 args) at Microsoft.FSharp.Core.PrintfImpl.capture@540[b,c,d](FSharpFunc`2 initialize, String fmt, Int32 len, FSharpList`1 args, Type ty, Int32 i) at Microsoft.FSharp.Core.PrintfImpl.gprintf[b,c,d,a](FSharpFunc`2 initialize, PrintfFormat`4 fmt) at FSI_0012.err@132-1.Invoke(String _arg1) in D:\Appdev\fsharp.actor\samples\Actor.fsx:line 134 at Microsoft.FSharp.Control.AsyncBuilderImpl.args@753.Invoke(a a) actor://main-pc/err_0 pre-stop Status: Errored actor://main-pc/err_0 stopped Status: Shutdown actor://main-pc/err_0 pre-restart Status: Restarting actor://main-pc/err_0 re-started Status: OK
we can see in the last 4 lines that the supervisor restarted this actor.
OneForAll
If any watched actor errors all children of this supervisor will be told to restart.
let oneforall = Supervisor.spawn <| Supervisor.Options.Create( strategy = Supervisor.Strategy.OneForAll, actorOptions = Actor.Options.Create("OneForAll") ) |> Supervisor.superviseAll [ Actor.spawn (Actor.Options.Create("err_1")) err; Actor.spawn (Actor.Options.Create("err_2")) err ] "err_1" ?<-- "Boo" "err_2" ?<-- "fail" // This yields Restarting (OneForAll actor://main-pc/err_1) due to error System.Exception: ERRRROROROR at FSI_0004.err@134-2.Invoke(String message) in D:\Appdev\fsharp.actor\samples\Actor.fsx:line 134 at Microsoft.FSharp.Core.PrintfImpl.go@523-3[b,c,d](String fmt, Int32 len, FSharpFunc`2 outputChar, FSharpFunc`2 outa, b os, FSharpFunc`2 finalize, FSharpList`1 args, Int32 i) at Microsoft.FSharp.Core.PrintfImpl.run@521[b,c,d](FSharpFunc`2 initialize, String fmt, Int32 len, FSharpList`1 args) at Microsoft.FSharp.Core.PrintfImpl.capture@540[b,c,d](FSharpFunc`2 initialize, String fmt, Int32 len, FSharpList`1 args, Type ty, Int32 i) at Microsoft.FSharp.Core.PrintfImpl.gprintf[b,c,d,a](FSharpFunc`2 initialize, PrintfFormat`4 fmt) at FSI_0004.err@132-1.Invoke(String _arg1) in D:\Appdev\fsharp.actor\samples\Actor.fsx:line 134 at Microsoft.FSharp.Control.AsyncBuilderImpl.args@753.Invoke(a a) actor://main-pc/err_2 pre-stop Status: OK actor://main-pc/err_2 stopped Status: Shutdown actor://main-pc/err_2 pre-restart Status: Restarting actor://main-pc/err_2 re-started Status: OK actor://main-pc/err_1 pre-stop Status: Errored actor://main-pc/err_1 stopped Status: Shutdown actor://main-pc/err_1 pre-restart Status: Restarting actor://main-pc/err_1 re-started Status: OK
we can see here that all of the actors supervised by this actor has been restarted.
Fail
A supervisor will terminate the actor that has errored
let fail = Supervisor.spawn <| Supervisor.Options.Create( strategy = Supervisor.Strategy.AlwaysFail, actorOptions = Actor.Options.Create("Fail") ) |> Supervisor.superviseAll [ Actor.spawn (Actor.Options.Create("err_3")) err; Actor.spawn (Actor.Options.Create("err_4")) err ] !!"err_3" <-- "fail" // This yields Terminating (AlwaysTerminate: actor://main-pc/err_1) due to error System.Exception: ERRRROROROR at FSI_0005.err@138-2.Invoke(String message) in D:\Appdev\fsharp.actor\samples\Actor.fsx:line 138 at Microsoft.FSharp.Core.PrintfImpl.go@523-3[b,c,d](String fmt, Int32 len, FSharpFunc`2 outputChar, FSharpFunc`2 outa, b os, FSharpFunc`2 finalize, FSharpList`1 args, Int32 i) at Microsoft.FSharp.Core.PrintfImpl.run@521[b,c,d](FSharpFunc`2 initialize, String fmt, Int32 len, FSharpList`1 args) at Microsoft.FSharp.Core.PrintfImpl.capture@540[b,c,d](FSharpFunc`2 initialize, String fmt, Int32 len, FSharpList`1 args, Type ty, Int32 i) at Microsoft.FSharp.Core.PrintfImpl.gprintf[b,c,d,a](FSharpFunc`2 initialize, PrintfFormat`4 fmt) at FSI_0005.err@136-1.Invoke(String _arg1) in D:\Appdev\fsharp.actor\samples\Actor.fsx:line 138 at Microsoft.FSharp.Control.AsyncBuilderImpl.args@753.Invoke(a a) actor://main-pc/err_1 pre-stop Status: Errored actor://main-pc/err_1 stopped Status: Shutdown
If you no longer require an actor to be supervised, then you can Unwatch
the actor, repeating the OneForAll above
let oneforallunwatch = Supervisor.spawn <| Supervisor.Options.Create( strategy = Supervisor.Strategy.OneForAll, actorOptions = Actor.Options.Create("OneForAll") ) |> Supervisor.superviseAll [ Actor.spawn (Actor.Options.Create("err_5")) err; Actor.spawn (Actor.Options.Create("err_6")) err ] Actor.unwatch !*"err_6" !!"err_5" <-- "fail" // We now see that one actor `err_1` has restarted Restarting (OneForAll actor://main-pc/err_1) due to error System.Exception: ERRRROROROR at FSI_0004.err@164-2.Invoke(String message) in D:\Appdev\fsharp.actor\samples\Actor.fsx:line 164 at Microsoft.FSharp.Core.PrintfImpl.go@523-3[b,c,d](String fmt, Int32 len, FSharpFunc`2 outputChar, FSharpFunc`2 outa, b os, FSharpFunc`2 finalize, FSharpList`1 args, Int32 i) at Microsoft.FSharp.Core.PrintfImpl.run@521[b,c,d](FSharpFunc`2 initialize, String fmt, Int32 len, FSharpList`1 args) at Microsoft.FSharp.Core.PrintfImpl.capture@540[b,c,d](FSharpFunc`2 initialize, String fmt, Int32 len, FSharpList`1 args, Type ty, Int32 i) at Microsoft.FSharp.Core.PrintfImpl.gprintf[b,c,d,a](FSharpFunc`2 initialize, PrintfFormat`4 fmt) at FSI_0004.err@162-1.Invoke(String _arg1) in D:\Appdev\fsharp.actor\samples\Actor.fsx:line 164 at Microsoft.FSharp.Control.AsyncBuilderImpl.args@753.Invoke(a a) actor://main-pc/err_1 pre-stop Status: Errored actor://main-pc/err_1 stopped Status: Shutdown actor://main-pc/err_1 pre-restart Status: Restarting actor://main-pc/err_1 re-started Status: OK
Full name: Supervision.err
type IActor =
interface
abstract member Link : IActor -> unit
abstract member Post : obj * IActor option -> unit
abstract member PostSystemMessage : SystemMessage * IActor option -> unit
abstract member Start : unit -> unit
abstract member UnLink : IActor -> unit
abstract member UnWatch : unit -> unit
abstract member Watch : IActor -> unit
abstract member add_OnRestarted : Handler<IActor> -> unit
abstract member add_OnStarted : Handler<IActor> -> unit
abstract member add_OnStopped : Handler<IActor> -> unit
...
end
Full name: FSharp.Actor.Types.IActor
--------------------
type IActor<'a> =
interface
inherit IActor
abstract member Post : 'a -> unit
abstract member Post : 'a * IActor option -> unit
abstract member Receive : int option -> Async<'a * IActor option>
abstract member Receive : unit -> Async<'a * IActor option>
end
Full name: FSharp.Actor.Types.IActor<_>
val string : value:'T -> string
Full name: Microsoft.FSharp.Core.Operators.string
--------------------
type string = System.String
Full name: Microsoft.FSharp.Core.string
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.async
abstract member IActor.Receive : int option -> Async<'a * IActor option>
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.failwithf
Full name: Supervision.oneforone
from FSharp.Actor
Full name: FSharp.Actor.Supervisor.spawn
{MaxFailures: int option;
Strategy: exn -> IActor<SupervisorMessage> -> IActor -> unit;
ActorOptions: Options<SupervisorMessage>;}
static member Create : ?maxFail:int option * ?strategy:(exn -> IActor<SupervisorMessage> -> IActor -> unit) * ?actorOptions:Options<SupervisorMessage> -> Options
static member Default : Options
Full name: FSharp.Actor.Supervisor.Options
from FSharp.Actor
{Id: string;
Mailbox: IMailbox<ActorMessage<'a>>;
Supervisor: IActor<SupervisorMessage> option;
Logger: ILogger;
Path: ActorPath;}
static member Create : ?id:string * ?mailbox:IMailbox<ActorMessage<'a>> * ?supervisor:IActor<SupervisorMessage> * ?logger:ILogger * ?address:ActorPath -> Options<'a>
static member Default : Options<'a>
Full name: FSharp.Actor.Actor.Options<_>
Full name: FSharp.Actor.Supervisor.superviseAll
Full name: FSharp.Actor.Actor.spawn
Full name: Supervision.oneforall
from FSharp.Actor.Supervisor
Full name: FSharp.Actor.Supervisor.Strategy.OneForAll
Full name: Supervision.fail
Full name: FSharp.Actor.Supervisor.Strategy.AlwaysFail
Full name: Supervision.oneforallunwatch
Full name: FSharp.Actor.Actor.unwatch