1
\$\begingroup\$

I'm trying to create an agent that holds on to Data and does further work with it upon receiving the Work message. Update is sent to the agent several times a minute, may potentially run longer than 10 seconds and signals the need to update Data.

Because update takes a lot of time, I've decided to do it on the background so as not to block the processing of Work messages. One option is to do the updating elsewhere and receive the new version as, say, NewData of Data message. However, I'd like to use new data as soon as possible, skipping the backlog of Work messages (MailboxProcessor.Scan would surely work, but I want to avoid it), so I keep the computation (actually, I had to resort to using a Task, because I could not find a way to check the status of an Async) as part of State and check it on every cycle.

Is there a better way to achieve the same behavior? I appreciate any comments and suggestions.

type Data = unit

type Message =
    | Work
    | Update

type State = { Data: Data; Updating: System.Threading.Tasks.Task<Data> option }

let update data = async {
    do! Async.Sleep 5000
    return data }

let work data = async {
    do! Async.Sleep 10 }

let mb = MailboxProcessor.Start (fun inbox ->
    let rec loop state = async {
        let state =
            match state.Updating with
            | Some t when t.IsFaulted ->
                { state with Updating = update state.Data |> Async.StartAsTask |> Some } // retry
            | Some t when t.IsCompleted ->
                { Data = t.Result; Updating = None }
            | _ -> state

        let! msg = inbox.Receive ()

        match msg with
        | Work ->
            work state.Data |> Async.Start
            return! loop state
        | Update ->
            match state.Updating with
            | Some _ -> return! loop state // old update still in progress, ignore
            | None -> return! loop { state with Updating = update state.Data |> Async.StartAsTask |> Some }
    }

    loop { Data = (); Updating = None }
)
\$\endgroup\$
2
  • \$\begingroup\$ Why not have two MailboxProcessors? \$\endgroup\$ Oct 29, 2016 at 5:31
  • \$\begingroup\$ How would you use the other one? As a repository of Data that also takes care of updates? \$\endgroup\$
    – nphx
    Oct 30, 2016 at 8:33

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Browse other questions tagged or ask your own question.