Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Awaiting an F# async task inside an akka.net actor{} expression

Tags:

f#

akka.net

Is it possible to wait (without blocking) on an Async<'t> within an Akka.Net actor computation? I want to achieve something similar to the following.

actor {
  let! msg = mailbox.Receive()
  match msg with
  | Foo ->
    let! x = async.Return "testing 123" // Some async function, return just an example
    () // Do something with result
}
like image 436
Oenotria Avatar asked Aug 09 '14 15:08

Oenotria


People also ask

Is it correct to say awaiting?

The verb 'await' must have an object - for example, 'I am awaiting your answer'. And the object of 'await' is normally inanimate, not a person, and often abstract. So you can't say, 'John was awaiting me'. The verb 'wait' can come in different structures.

Is awaiting or is awaited?

to wait for or be waiting for something: He's anxiously awaiting his test results. A marvellous reception awaited me on my first day at work. The long/eagerly awaited sequel is now available online.

What does awaiting mean?

1a : to wait for We are awaiting his arrival. await a decision. b : to remain in abeyance until a treaty awaiting ratification. 2 : to be in store for He wonders what awaits him next. 3 obsolete : to lie in wait for.


2 Answers

No you can't use async / await or any variant thereof inside an actor's mailbox and get safe results.

Each actor maintains its own context, which includes important details like the Sender of the previous message and other important pieces of state which might change. Actors process messages serially, so as soon as the call inside its mailbox finishes it immediately begins processing its next message - if you put an await call inside the mailbox, the actor will be processing a totally different message than the one you started with by the time your await call returns.

A better pattern for leveraging asynchronous calls and the TAP inside actors is to use the PipeTo pattern. It looks like we don't have any documentation for this yet at http://akkadotnet.github.io/, so I'll give you a real-world code sample (in C#):

    public void Handle(ExplicitReplyOperation<CampaignsForAppRequest> message)
    {
        Context.IncrementMessagesReceived();
        _loaderActor.Ask(message.Data).ContinueWith(r =>
        {
            var campaigns = (IList<Campaign>)r.Result;
            message.Originator.Tell(new CampaignsForAppResponse()
            {
                AppId = message.Data.AppId,
                ActiveCampaigns = campaigns
            }, ActorRef.NoSender);
            return campaigns;
        }).PipeTo(Self);
    }

In this sample I have a TypedActor that continues a Task, does some post-processing, and then uses the PipeTo operator (an Akka.NET extension method you can apply to any Task object) to pipe the results of the task into this actor's mailbox once the operation is finished. That way I can close over any of the state I need and my actor can continue processing messages in a safe way while this async operation continues.

like image 106
Aaronontheweb Avatar answered Oct 17 '22 10:10

Aaronontheweb


This now seems to be possible!

let system = ConfigurationFactory.Default() |> System.create "FSharpActors"
let asyncActor =
  spawn system "MyActor"
  <| fun mailbox ->
    let rec loop() =
      actor {
      let! name = mailbox.Receive()
      Akka.Dispatch.ActorTaskScheduler.RunTask(fun () ->
      async {
        printfn "Hello %s" name
        do! Async.Sleep 5000
        } |> Async.StartAsTask :> Threading.Tasks.Task)
      return! loop()
      }

    loop()

asyncActor <! "Alice"
asyncActor <! "Bob"
asyncActor <! "Eve"
like image 3
Oenotria Avatar answered Oct 17 '22 11:10

Oenotria