I have tried following code to view/capture dead letters but it is not working in a way it should. What I am missing.exactly? My aim is just to view all the dead letters that are being delivered to deadletters actor.
let system = ActorSystem.Create("FSharp")
let echoServer =
spawn system "EchoServer"
<| fun mailbox ->
let rec loop() =
actor {
let! message = mailbox.Receive()
match box message with
| :? string ->
printfn "Echo '%s'" message
return! loop()
| _ -> failwith "unknown message"
}
loop()
let boolval = system.EventStream.Subscribe(echoServer,typedefof<DeadLetterActorRef>)
echoServer.Tell("First Message")
echoServer.Tell("Second Message")
system.DeadLetters.Tell("Dead Message")
When you subscribe to the event bus, you're subscribing to the type of message published to the bus. In the code you posted you registered the subscriber to the DeadLetterActorRef message, whereas dead letters are published in the form of DeadLetter messages. So in your case, you just need to change your subscription to
let boolval = system.EventStream.Subscribe(echoServer, typeof<DeadLetter>)
Related
I created the following test code - .Net core 2.1 console application. It prints the following message only
TestActor received message MyTask ("Test1","Test1") from [akka://MySystem/user/Scheduler#1426101451]
But the message Ok 0 cannot be received by the actor scheduler?
open System
open Akka.FSharp
open Akka
type MyTask = MyTask of item1: string * item2: string
let system = System.create "MySystem" <| Configuration.load ()
let scheduler (actors: Actor.IActorRef) (mailbox: Actor<Result<int, string>>) =
let rec loop (list: int list list) = actor {
let! m = mailbox.Receive ()
let sender = mailbox.Sender ()
let akkaName = mailbox.Self.Path.Name
printfn "%s received message %A from %A" akkaName m sender
return! loop []
}
actors <! MyTask("Test1", "Test1")
loop []
let processor (mailbox: Actor<MyTask>) =
let rec loop () = actor {
let! m = mailbox.Receive ()
let sender = mailbox.Sender ()
let akkaName = mailbox.Self.Path.Name
printfn "%s received message %A from %A" akkaName m sender
sender <! Ok 0 // scheduler cannot receive this message?
return! loop ()
}
loop ()
[<EntryPoint>]
let main argv =
let actor = spawn system "TestActor" processor
spawn system "Scheduler" (scheduler actor) |> ignore
system.WhenTerminated.Wait()
0
Update:
It works after I changed the parameter from (mailbox: Actor<Result<int, string>>) to (mailbox: Actor<_>)?
The scheduler isn't the sender of the MyTask message to which the processor is replying, because you are doing the tell (<!) from outside the actor computation. That means it's basically being sent with no sender. You can use the Tell method on IActorRef to send with an explicit sender, since you want to send it from outside the context of your actor computation:
actors.Tell(MyTask("Test1", "Test1"), mailbox.Self)
EDIT
Another issue is that the mailbox parameter to the scheduler is typed as Actor<Result<int, string>>, but since Ok 0 will be inferred as Result<int,obj> in your context, it won't match the actor type signature, and the message will be ignored. When defining an actor with a specific message type, any messages of a different type will be ignored.
Is it possible to wait on the mailboxprocessor, following code works in F# interactive but is there a way to wait on it in an application or a unit test?
[<TestMethod>]
member this.TestMailboxProcessor() =
let mailboxProcessor = MailboxProcessor<string>.Start(fun inbox ->
async {
while true do
let! msg = inbox.Receive()
printfn "agent got message %s" msg // too late, UnitTest exits
}
)
mailboxProcessor.Post "ping"
Console.WriteLine "message posted" // I see this in the console
Assert.IsTrue(true)
It's not possible in exactly this scenario, but you can define your message type to include an AsyncReplyChannel<'t>, which then allows you to use MailboxProcessor.PostAndReply instead of Post. This way the calling code can (either synchronously or asynchronously) wait for a response value, or at least an indication that the processing is done.
Your modified source code may look like this:
[<TestMethod>]
member this.TestMailboxProcessor() =
let mailboxProcessor =
MailboxProcessor<string * AsyncReplyChannel<unit>>.Start(fun inbox ->
async {
while true do
let! msg, replyChannel = inbox.Receive()
printfn "agent got message %s" msg
(*
Reply takes a value of the generic param of
AsyncReplyChannel<'t>, in this case just a unit
*)
replyChannel.Reply()
}
)
(*
You can't create an AsyncReplyChannel<'t> value, but this does it for you.
Also always, always use timeouts when awaiting message replies.
*)
mailboxProcessor.PostAndReply(
(fun replyChannel -> "ping", replyChannel),
timeout = 1000)
(* This gets printed only after the message has been posted and processed *)
Console.WriteLine "message posted"
Assert.IsTrue(true)
MailboxProcessors are a bit tricky topic though, so make sure you always use timeouts, otherwise in case of errors in your code, or exceptions killing the message loop, your code would hang forever. Not good in tests, even worse in production.
You should use PostAndAsyncReply or PostAndReply (blocking version)
let replyAgent = MailboxProcessor.Start(fun inbox ->
let rec loop() =
async {
let! (replyChannel: AsyncReplyChannel<_>), msg = inbox.Receive()
replyChannel.Reply (sprintf "replied for message: %A" msg)
return! loop()
}
loop() )
let reply = replyAgent.PostAndReply(fun replCh -> replCh, "Hi")
printfn "%s" reply //prints "replied for message: Hi"
Issue:
I am struggling to understand why my Reporter actor is not receiving messages based on the following statement that's in my Generator actor:
reporter <! Message input
My reporter actor is the following:
let reporterActor (mailbox:Actor<_>) =
let rec loop() = actor { let! msg = mailbox.Receive()
match msg |> box :?> Command with
| Start -> ()
| Message v -> printf "%s" v
| Exit -> mailbox.Context.System.Terminate() |> ignore }
loop() |> ignore
Basically, a console is launched that accepts input from the user. My Generator actor forwards that input to my Reporter actor. However, the code above never gets executed.
The code is the following:
module Main
open System
open Akka.FSharp
open Akka.Actor
open Actors
type Command =
| Message of string
| Start | Exit
let reporterActor (mailbox:Actor<_>) =
let rec loop() = actor { let! msg = mailbox.Receive()
match msg |> box :?> Command with
| Start -> ()
| Message v -> printf "%s" v
| Exit -> mailbox.Context.System.Terminate() |> ignore }
loop() |> ignore
let generatorActor (reporter:IActorRef) (mailbox:Actor<_>) message =
let handle input = match input with
| "exit" -> mailbox.Context.System.Terminate |> ignore
| _ -> reporter <! Message input
handle (Console.ReadLine().ToLower())
[<EntryPoint>]
let main argv =
let system = System.create "system" (Configuration.load())
let reporterActor = spawn system "reporterActor" (actorOf(reporterActor))
let generatorActor = spawn system "generatorActor" (actorOf2(generatorActor reporterActor))
generatorActor <! Start
system.AwaitTermination ()
0
Update:
I learned that I could trigger my Reporter actor by replacing the mailbox parameter with an arbitrary message parameter:
let reporterActor message =
match message |> box :?> Command with
| Start -> ()
| Message v -> printf "Reporting: %s" v
| Exit -> failwith "Kill this!"
I still don't understand when I should use a mailbox parameter versus when I should rely on a message parameter.
The difference is in how actorOf and actorOf2 work.
actorOf in conjunction with spawn creates an actor as a child of the root of the system which will handle messages with the function 'Message -> unit that was passed to it.
actorOf2 in in conjunction with spawn creates an actor as a child of the actor that you passed in and the child will handle the messages with the function 'Message -> unit that was passed.
Your original function signature for reporter actor was:
Actor<'Message> -> unit
and you used spawn system "reporterActor" (actorOf(reporterActor))
In this case you were saying that the message type that the new actor that was created would receive would be of type Actor<'Message> . This compiled because actorof just expects a function that takes a 'Message, and a 'Message is generic therefore Actor<'Message> satisfied the 'Message parameter.
When you updated the signature of reporterActor you change the signature to 'Message -> unit which is what actorOf is actually intended to accept.
In short generics allowed your code to compile since 'Message isn't really restricted, nor should it really be.
From: http://getakka.net/docs/FSharp%20API
actorOf (fn : 'Message -> unit) (mailbox : Actor<'Message>) :
Cont<'Message, 'Returned> - uses a function, which takes a message as
the only parameter. Mailbox parameter is injected by spawning
functions.
actorOf2 (fn : Actor<'Message> -> 'Message -> unit) (mailbox :
Actor<'Message>) : Cont<'Message, 'Returned> - uses a function, which
takes both the message and an Actor instance as the parameters.
Mailbox parameter is injected by spawning functions. Example:
> let handleMessage (mailbox: Actor<'a>) msg =
> match msg with
> | Some x -> printf "%A" x
> | None -> ()
>
> let aref = spawn system "my-actor" (actorOf2 handleMessage) let
> blackHole = spawn system "black-hole" (actorOf (fun msg -> ()))
spawn (actorFactory : IActorRefFactory) (name : string) (f :
Actor<'Message> -> Cont<'Message, 'Returned>) : IActorRef - spawns an
actor using a specified actor computation expression. The actor can
only be used locally.
All of these functions may be used with either the actor system or the
actor itself. In the first case the spawned actor will be placed under
/user root guardian of the current actor system hierarchy. In the
second option the spawned actor will become a child of the actor used
as the actorFactory parameter of the spawning function.
Please see last edit.
Apologies for the newbie question. I am trying to implement something in F# using Akka.net. I'm very new to F# and I have only used Akka from Scala. Basically I am trying to implement something that's pretty easy in Scala, namely making an Actor do different things based on the type of message it receives.
My code is below and it's a slight modification of the hello world example lifted from the akka.net website. I believe a first problem with my code is that it does record pattern matching instead of type pattern matching, however I was unable to write a type match one without compilation errors... Any help will be greatly appreciated. Thank you.
open Akka.FSharp
open Actors
open Akka
open Akka.Actor
type Entries = { Entries: List<string>}
let system = ActorSystem.Create "MySystem"
let feedBrowser = spawn system "feedBrowser" <| fun mailbox ->
let rec loop() = actor {
let! msg = mailbox.Receive()
match msg with
| { Entries = entries} -> printf "%A" entries
| _ -> printf "unmatched message %A" msg
return! loop()}
loop()
[<EntryPoint>]
let main argv =
feedBrowser <! "abc" // this should not blow up but it does
system.AwaitTermination()
0
Edit: the error is a runtime one, System.InvalidCastException, unable to cast object of type String to Entries.
Later edit: I got this to work with this change, downcasting to Object:
let feedBrowser = spawn system "feedBrowser" <| fun mailbox ->
let rec loop() = actor {
let! msg = mailbox.Receive()
let msgObj = msg :> Object
match msgObj with
| :? Entries as e -> printfn "matched message %A" e
| _ -> printf "unmatched message %A" msg
return! loop()}
loop()
Now these two lines work correctly
feedBrowser <! "abc"
feedBrowser <! { Entries = ["a"; "b"] }
the first one prints "unmatched message abc" and the second outputs the entries.
Is there a better way of going about this, without the cast? Does akka.net have something specifically for this case?
Thank you.
You should use a Discriminated Union (the Command type in this example). Then you can pattern match its options.
type Entries = { Entries: List<string>}
type Command =
| ListEntries of Entries
| OtherCommand of string
let stack() =
let system = ActorSystem.Create "MySystem"
let feedBrowser = spawn system "feedBrowser" <| fun mailbox ->
let rec loop() = actor {
let! msg = mailbox.Receive()
match msg with
| ListEntries { Entries = entries} -> printf "%A" entries
| OtherCommand s -> printf "%s" s
return! loop() }
loop()
And to send the message you should use:
feedBrowser <! OtherCommand "abc"
feedBrowser <! ListEntries { Entries = ["a"; "b"] }
It's important to say that the send operator has the following signature:
#ICanTell -> obj -> unit
So, if you pass an message with a different type, like a string, it'll raise an exception.
I wonder, why MailboxProcessor's default strategy of handling exceptions is just silently ignore them. For example:
let counter =
MailboxProcessor.Start(fun inbox ->
let rec loop() =
async { printfn "waiting for data..."
let! data = inbox.Receive()
failwith "fail" // simulate throwing of an exception
printfn "Got: %d" data
return! loop()
}
loop ())
()
counter.Post(42)
counter.Post(43)
counter.Post(44)
Async.Sleep 1000 |> Async.RunSynchronously
and nothing happens. There is no fatal stop of the program execution, or message box with "An unhandled exception" arises. Nothing.
This situation becomes worse if someone uses PostAndReply method: a guaranteed deadlock as the result.
Any reasons for such behavior?
There is an Error event on the MailboxProcessor.
http://msdn.microsoft.com/en-us/library/ee340481
counter.Error.Add(fun e -> printfn "%A" e)
Of course, you can do something like Tomas' solution if you want to exert fine control yourself.
I think the reason why the MailboxProcessor in F# does not contain any mechanism for handling exceptions is that it is not clear what is the best way for doing that. For example, you may want to have a global event that is triggered when an unhandled exception happens, but you may want to rethrow the exception on the next call to Post or PostAndReply.
Both of the options can be implemented based on the standard MailboxProcessor, so it is possible to add the behaviour you want. For example, the following snippet shows HandlingMailbox that adds a global exception handler. It has the same interface as normal MailboxProcessor (I omitted some methods), but it adds OnError event that is triggered when an exception happens:
type HandlingMailbox<'T> private(f:HandlingMailbox<'T> -> Async<unit>) as self =
let event = Event<_>()
let inbox = new MailboxProcessor<_>(fun inbox -> async {
try
return! f self
with e ->
event.Trigger(e) })
member x.OnError = event.Publish
member x.Start() = inbox.Start()
member x.Receive() = inbox.Receive()
member x.Post(v:'T) = inbox.Post(v)
static member Start(f) =
let mbox = new HandlingMailbox<_>(f)
mbox.Start()
mbox
To use it, you would write the same code as what you wrote before, but you can now handle exceptions asynchronously:
let counter = HandlingMailbox<_>.Start(fun inbox -> async {
while true do
printfn "waiting for data..."
let! data = inbox.Receive()
failwith "fail" })
counter.OnError.Add(printfn "Exception: %A")
counter.Post(42)