I'd like to have an agent that acts as an SMTP server that asynchronously waits for emails and also services requests to retrieve the list of emails received. The agent would look something like:
let agent = Agent.Start(fun inbox ->
let rec loop emails = async {
let! email = ReceiveEmail()
let emails = email::emails
let! emailStatusRequest = inbox.Receive()
match emailStatusRequest with
| Get channel -> channel.Reply emails
return! loop emails }
loop [])
This would wait for an email and then wait for a status request. How would I decouple the ordering so that the agent responds to whichever event happens first - the email received event or the request to get the emails event? Is an agent even the right tool for modelling this?
I would move the ReceiveEmail
part in it's own async-loop and have it post messages to your agent.
something like this (warning: not tested - treat as pseudo-code):
type AgentCommands =
| Received of Email
| StatusRequest of RequestParams
| ...
let agent = Agent.Start(fun inbox ->
let rec loop emails = async {
let! cmd = inbox.Receive
match cmd with
| Received email ->
let emails = email::emails
return! loop emails
| StatusRequest emailStatusRequest ->
match emailStatusRequest with
| Get channel -> channel.Reply emails
return! loop emails }
loop [])
let receiveLoop = async {
while true do
let! email = ReceiveEmail()
agent.Post (Received email)
} |> Async.Start
of course you probably need to at CancellationToken
support ... you'll get it ;)