-
-
Save kunjee17/3e6d4c6f263a3c543b89 to your computer and use it in GitHub Desktop.
[<CLIMutableAttribute>] | |
[<AliasAttribute("hello")>] | |
type HelloDb = | |
{ Name : string } | |
[<LiteralAttribute>] | |
let connStr = "Server = localhost; Port = 5432; Database = database; User Id = username; password = password;" | |
let dbfactory = OrmLiteConnectionFactory(connStr, PostgreSqlDialect.Provider) | |
let agent = | |
MailboxProcessor.Start(fun inbox -> | |
//let db = dbfactory.Open(); persistance open connection. | |
let rec messageLoop() = | |
async { | |
let! (msg : Hello) = inbox.Receive() | |
do use db = dbfactory.Open() | |
//do some processing | |
db.InsertAsync(msg) | |
|> Async.AwaitTask | |
|> ignore | |
printfn "%A" msg.Name | |
do! Async.Sleep(rnd.Next(100, 1000)) | |
return! messageLoop() | |
} | |
messageLoop()) | |
agent.Post {Name:"Kunjan"} | |
//How can use this agent to insert data. Because if they are queue I guess it is ok to use persistance open connection. Here I am not doing it | |
//but I guess that very much possible |
@swlaschin thank for reply. I have updated my gist according to it. And its working. That is it right it always works with when you. :P.
One more question. If I use "use" keyword normally I should not need to close connection but I guess queue is slow in garbage collection and I am throttling database. So, I need to manually close the connection.
So, which option is better. I can use "let" and don't close connection at all. Or keep using "use" and close connection manually?
Yes, I would manually close the connection before the end.
use db = dbfactory.Open()
...
db.Close()
return! messageLoop()
In fact, I'm not sure that the connection will be closed automatically, as the scope is never exited until the agent stops!
use db = dbfactory.Open()
...
return! messageLoop()
// never reach this point until the agent stops, so dispose not called!
Here's an example that demonstrates this:
let newDisposable id = {
new System.IDisposable with
member this.Dispose() =
printfn "disposing %i" id
}
let rec loop n =
use db = newDisposable n
printfn "loop %i" n
if n = 0 then
printfn "Loop stopped"
else
// recurse
loop (n-1)
// use is not disposed here
// test
loop 5
Output is:
loop 5
loop 4
loop 3
loop 2
loop 1
loop 0
Loop stopped
disposing 0
disposing 1
disposing 2
disposing 3
disposing 4
disposing 5
Is it worth looking at the use expression which takes in a lambda? Might that allow you to better control scope of the connection?
@swlaschin that's new. So, my db is staying there always. Hmmm, I close the connection then I guess. Thanks for reply. First time doing some practical with agents and feeling like James Bond. ;)
As Isaac said, you can use a using
expression, or alternatively, create a new scope by indenting with a do
at the top, like this:
let rec disposingLoop n =
do
// start new scope
use db = newDisposable n
printfn "inside loop %i" n
if n = 0 then
printfn "Loop stopped"
else
disposingLoop (n-1)
disposingLoop 5
Output is:
inside loop 5
disposing 5
inside loop 4
disposing 4
inside loop 3
disposing 3
inside loop 2
disposing 2
inside loop 1
disposing 1
inside loop 0
disposing 0
Loop stopped
@swlaschin and @isaacabraham how can I use do keyword within async keyword. It is giving me compilation error.
If to await an Async, it's do!
@isaacabraham I tried that also. It also didn't work. Can you please give example in context of gist? It will be great help.
@swlaschin and @isaacabraham. I guess I make it working. Please have a look that if it is good as per code. It is working now without closing connection.
And ya we can't use any bang thing in do clause. means that do! will be outside of that clause. Or anything that I should be asynced...
PS: ref - http://stackoverflow.com/questions/7433426/f-async-dispose
Looks good to me. That SO question has good answers too!
According to the source at https://github.com/ServiceStack/ServiceStack.OrmLite/blob/master/src/ServiceStack.OrmLite/OrmLiteWriteApiAsync.cs#L31 it returns a
Task<long>
, so you need to turn the Task into an Async, and then ignore the return value (if you want).In other words, use
Async.AwaitTask
to turn theTask
into anAsync
, and then optionally useAsync.Ignore
.You already have the
Async.AwaitTask
, so you could write:or