Synchronously Await an Async Workflow Using Observable.guard

The other day, I couldn’t figure out how to Synchronously wait for an Async workflow to complete. I was pretty sure I needed to use Observable.guard, I just couldn’t wrap my head around how to use it. This morning I was on a mission to figure it out.

open System
open FSharp.Control

let event = new Event<_>()

let createObservableByExecutingAsync asyncToExecute =
    event.Publish
    |> Observable.guard(fun _ -> 

        let asyncOperation = async {
            asyncToExecute
            |> Async.RunSynchronously

            event.Trigger(())
        }
        
        printfn "Start Executing Async Operation"

        Async.Start asyncOperation

        printfn "End Executing Async Operation"
    )

let someAsyncOperation = async {
        printfn "Async Operation"
    }

let asyncWorker = createObservableByExecutingAsync someAsyncOperation

printfn "Start Waiting for Async Result"

Async.AwaitObservable asyncWorker
|> Async.RunSynchronously

printfn "End Waiting for Async Result"

Console.ReadLine()
|> ignore

This bit of code produces the most beautiful output of…

Start Waiting for Async Result 
Start Executing Async Operation
End Executing Async Operation
Async Operation
End Waiting for Async Result

Figuring that out makes me feel better, but the bigger realization was that I didn’t need Observable.guard at all. I needed Async.AwaitObservable.

open System
open FSharp.Control
open RateLimiting
 
type Messages =
    | Message of string
 
type Responses =
    | Response of string
 
let operationFunction (message: Messages) =
    match message with
    | Message(input) -> Response(sprintf "Response: %s" input)
 
let agent =
    RateLimitedAgent(operationFunction, 4, 1000)
 
let event = new Event<_>()

let someAsyncOperation (response:Responses) = async {
        printfn "Async Response"
        event.Trigger(())
    }

agent.QueueItem({payload = Message("Awaited Payload") ; response = Some(someAsyncOperation)})
|> Async.Start

printfn "Start Waiting for Async Result"

Async.AwaitObservable event.Publish
|> Async.RunSynchronously

printfn "End Waiting for Async Result"

Console.ReadLine()
|> ignore
Start Waiting for Async Result
Async Response
End Waiting for Async Result

I love watching this stuff work.

Async Wait Operation