Reputation: 91
I have a piece of code that adds a row to a database when a MailboxProcessor
receives a message. It works correctly when run in fsi, but it hangs when compiled to an exe. The script is as follows:
#r "../packages/Newtonsoft.Json/lib/net40/Newtonsoft.Json.dll"
#r "../packages/SQLProvider/lib/FSharp.Data.SqlProvider.dll"
open Newtonsoft.Json
open FSharp.Data.Sql
open System
let [<Literal>] ResolutionPath = __SOURCE_DIRECTORY__ + "/../build/"
let [<Literal>] ConnectionString = "Data Source=" + __SOURCE_DIRECTORY__ + @"/test.db;Version=3"
// test.db is initialized as follows:
//
// BEGIN TRANSACTION;
// CREATE TABLE "Events" (
// `id`INTEGER PRIMARY KEY AUTOINCREMENT,
// `timestamp` DATETIME NOT NULL
// );
// COMMIT;
type Sql = SqlDataProvider<
ConnectionString = ConnectionString,
DatabaseVendor = Common.DatabaseProviderTypes.SQLITE,
ResolutionPath = ResolutionPath,
IndividualsAmount = 1000,
UseOptionTypes = true >
let ctx = Sql.GetDataContext()
let agent = MailboxProcessor.Start(fun (inbox:MailboxProcessor<String>) ->
let rec loop() =
async {
let! msg = inbox.Receive()
match msg with
| _ ->
let row = ctx.Main.Events.Create()
row.Timestamp <- DateTime.Now
printfn "Submitting"
ctx.SubmitUpdates()
printfn "Submitted"
return! loop()
}
loop()
)
agent.Post "Hello"
When compiled to an exe, "Submitting" is printed, but then it hangs. If you want to try it out, the full code is on github here
Upvotes: 4
Views: 200
Reputation: 91
It seems the problem was that the main thread was exiting before the MailboxProcessor
could process it's mailbox. FSI is long-lived and so this wasn't happening there. I changed:
[<EntryPoint>]
let main argv =
agent.Post "Hello"
agent.Post "Hello again"
0
to
[<EntryPoint>]
let main argv =
agent.Post "Hello"
agent.Post "Hello again"
let waitLoop = async {
while agent.CurrentQueueLength > 0 do
printfn "Sleeping"
do! Async.Sleep 1000
}
Async.RunSynchronously waitLoop
0
and now the code executes as I had intended.
Upvotes: 5