Skip to content

Instantly share code, notes, and snippets.

@kunjee17
Last active October 25, 2015 18:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kunjee17/3e6d4c6f263a3c543b89 to your computer and use it in GitHub Desktop.
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
Copy link

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 the Task into an Async, and then optionally use Async.Ignore.

You already have the Async.AwaitTask, so you could write:

let! insertResult = db.InsertAsync(msg) |> Async.AwaitTask

or

do! db.InsertAsync(msg) |> Async.AwaitTask |> Async.Ignore

@kunjee17
Copy link
Author

@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?

@swlaschin
Copy link

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

@isaacabraham
Copy link

Is it worth looking at the use expression which takes in a lambda? Might that allow you to better control scope of the connection?

@kunjee17
Copy link
Author

@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. ;)

@swlaschin
Copy link

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

@kunjee17
Copy link
Author

@swlaschin and @isaacabraham how can I use do keyword within async keyword. It is giving me compilation error.

@isaacabraham
Copy link

If to await an Async, it's do!

@kunjee17
Copy link
Author

@isaacabraham I tried that also. It also didn't work. Can you please give example in context of gist? It will be great help.

@kunjee17
Copy link
Author

@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

@swlaschin
Copy link

Looks good to me. That SO question has good answers too!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment