-
Notifications
You must be signed in to change notification settings - Fork 44
Creating an actor
Unlike C# actors, which represent object oriented nature of the language, F# is able to define an actor's logic in more functional way. It's done by using actor
computation expression. In most cases, an expression inside an actor is expected to be represented as self-invoking recursive function - using mutually recursive functions in this context is allowed and even desired, i.e. to create more advanced constructs like Finite State Machines.
Each actor returning point should point to either recursive loop call or return an Effect.
Example:
let helloRef = spawn system "hello-actor" <| props(fun context ->
let rec loop () = actor {
let! msg = context.Receive ()
match msg with
| "stop" -> return Stop // effect - stops current actor
| "unhandle" -> return Unhandled // effect - marks message as unhandled
| x ->
printfn "%s" x
return! loop ()
}
loop ())
Since construct used in an example above is quite popular, you may also use following shorthand functions to define message handler's behavior:
-
actorOf (fn : 'Message -> #Effect<'Message>) (mailbox : Actor<'Message>) : Effect<'Message>
- uses a function, which takes a message as the only parameter. Context parameter is injected by spawning functions. -
actorOf2 (fn : Actor<'Message> -> 'Message -> #Effect<'Message>) (mailbox : Actor<'Message>) : Effect<'Message>
- uses a function, which takes both the message and an actor's context as the parameters. Context itself is injected by a spawning functions.
Example usage:
let rec handleMessage state (context: Actor<'a>) = function
| "print" -> printf "%A" state |> ignored // returned effect - stay the same
| x -> become (handleMessage (x::state)) // returned effect - update the actor's state
let aref = spawn system "my-actor" (actorOf2 (handleMessage [])) // init actor state with empty list
Since some of the functional behaviors are quite popular, you can find them inside Akkling.Behaviors
module. Currently their list consist of:
-
ignore (context:Actor<'Message>) : Effect<'Message>
- an empty behavior, which will automatically ignore all incoming messages. -
echo (context: Actor<'Message>) : Effect<'Message>
- it will resend message back to it's sender. -
printf (fmt: Printf.TextWriterFormat<'Message->unit>) (context: Actor<'Message>) : Effect<'Message>
- takes format string and print's each incoming message using that format.
Example:
let blackhole = spawnAnonymous system Behaviors.ignore
let echoRef = spawnAnonymous system Behaviors.echo
Props<'Message>
is a typed descriptor containing all information necessary to create particular actor type. There are many different props methods, depending on additional features of actors (like support for eventsourcing). By default props
and propse
are two functions used to produce props from actor functions. Difference between them is that props
takes simple actor behavior function, while propse
takes a quotation which can be serialized and compiled on the other side.
Paragraph above already has shown, how actors may be created with help of the spawning function. There are several spawning function, which may be used to instantiate actors:
-
spawn (actorFactory : IActorRefFactory) (name : string) (p: Props<'Message>) : IActorRef<'Message>
- spawns an actor using specified actor computation expression. -
spawnAnonymous (actorFactory : IActorRefFactory) (p: Props<'Message>) : IActorRef<'Message>
- spawns an actor without need of providing actor's name.
All of these functions may be used with either actor system or actor context. In the first case spawned actor will be placed under /user root guardian of the current actor system hierarchy. In second option spawned actor will become child of the actor used as [actorFactory] parameter of the spawning function.
- Introduction
- Bootstrapping actor system
- Creating an actor
- Static type safety
- Effects
- Managing actor's lifecycle
- Supervision strategies
- Event bus
- Logging
- Socket I/O
- Persistence
- Cluster sharding