The Work method creates a long-term process that ultimately needs to be stopped. The best way to present this in F # would be to use asynchronous workflows - an asynchronous workflow can be paused without blocking the thread (so you don't need Thread.Sleep ), and it can be easily undone with the CancellationToken .
Otherwise, your code looks good to me. I made some minor changes (for example, use take in the F # query syntax, which is a small function).
I also don't quite understand why your code has two nested while . It's necessary? If not, I think you could write something like:
member this.Work() = async { logger.Info "Starting work" while true do do! Async.Sleep(1000) use context = contextFactory.GetEntities() let unsentEmails = query { for q in context.QueueItems do where (q.Error = null) select q.Email take 10 } unsentEmails |> Array.map MapToMessage |> Array.iter (fun (email, message) -> try mailClient.SendMail(message) email.DateSent <- new Nullable<DateTime>(DateTime.UtcNow) context.QueueItems.Remove(email.QueueItem) |> ignore with ex -> logger.Error(ex) email.QueueItem.Error <- ex.ToString()) context.SaveChanges() |> ignore logger.Info (sprintf "Sent %d emails" unsentEmails.Length) logger.Info "Work complete" }
To start the process (and stop it later), you should write something like:
// Start the work let cts = new CancellationTokenSource() Async.Start(worker.Work(), cts.Token) // Stop the worker cts.Cancel()
source share