What is a good approach to wrapping an Async<'t>
such that only one of them can run at a time?
I have come up with a solution using MailboxProcessor
although I wonder if a more lightweight mechanism is possible.
open System
open System.Threading.Tasks
let oneAtATime (workflow : Async<'t>) =
let rec logic (taskCache : Task<'t> option) (inbox : MailboxProcessor<AsyncReplyChannel<Task<'t>>>) =
async {
let! channel = inbox.Receive()
match taskCache with
| Some task when not task.IsCompleted ->
channel.Reply(task)
return! logic taskCache inbox
| _ ->
let task = Async.StartAsTask workflow
channel.Reply(task)
return! logic (Some task) inbox
}
let actor = MailboxProcessor.Start(logic None)
async {
let! t = actor.PostAndAsyncReply(id)
return! Async.AwaitTask t
}