I've got a centralized database connector: (define dbh (virtual-connection (connection-pool (thunk (postgresl-connect ...)))))
This gets passed around from handle to handle and into various temporary or ongoing worker threads. Thinking about it, I'd like to check that I've understood it properly: - The virtual connection (VC) itself is very lightweight and it's fine for it to persist throughout the run of the program. - The connection pool (CP) inside the VC will maintain a (small?) collection of persistent connections to hand out upon request, so I'm not paying the connection-setup-time penalty every time I use it. - It's also fine to pass the VC into other threads. It will be shared state between the threads, but the CP will keep their connections isolated and when the threads terminate it won't interfere. (Ignore pathological cases -- obviously if I give it to enough threads and they all use it at once then we might exceed the DB limits on number of handles, speed, bandwidth, etc.) - The CP will create more connections as needed, so there's no need to worry about running out (barring pathological cases). - db connections will get garbage collected normally, at the marked points: #lang racket (require db) (begin ; outer begin (define dbh (virtual-connection (connection-pool (thunk (postgresql-connect #:user "x" #:database "x" #:password "x" #:port 5432 ))))) ; closes 'define dbh' (define (foo dbh-A) ; dbh will be passed in (begin ; inner begin (define dbh-B dbh) ; (eq? dbh-A dbh-B) => #t (for ((i 10)) (thread (thunk (sleep (floor (* 10 (random)))) (query-value dbh-A "select 7") (disconnect dbh-A) ; this is a no-op since dbh-A is a virtual connection, not an actual connection (with-handlers ((exn:fail? (lambda (e) (displayln e)))) (prepare dbh "select * from users where username = $1") ; raises "cannot prepare statement with virtual connection" exception );with-handlers (sleep (floor (* 10 (random)))))))) ); closes foo (foo dbh) ); closes outer begin (sleep 20) ; without this all the other threads would be closed when the main thread ended By the time we get to 'sleep 20' dbh is out of scope but still visible to the various worker threads. dbh will not be GC'd until all those threads have ended, even after all those threads have executed the 'disconnect' line and thrown the exception. Assuming I've understood all that correctly, my last question would be how to get around the 'can't do prepare with a virtual connection' issue for situations where I've been passed a connection (perhaps from third party code) and it might or might not be virtual. First, to dispose of some quibbles: - One answer is "well, don't do that." Write a contract on the function that mandates the connection being non-virtual. - Another is "well, don't do that." Test if the connection is virtual and, if so, don't use prepare. - Another is "well, don't do that." Pass around a dsn instead of a VC and generate connections as needed. None of these is terribly satisfying. The first violates the principle of "be generous in what you accept and strict in what you emit", the second gives up a lot of speed if we were in a situation where we wanted to use 'prepare' in the first place, and the third isn't feasible since I won't always have control over what a third-party library emits. My ideal solution would be something like this: (define (myfunc a-handle) (define dbh (if (virtual-connection? a-handle) (my-function-to-do-connect-with-dsn (get-dsn-from a-handle)) a-handle)) (define sth (prepare dbh "select foo from bar where baz = $1")) ...stuff... ) In other words, check if the connection is virtual and, if so, extract the dsn from it and use that to create a non-virtual connection. Is there a way to do that? I've been through the db module docs and Google but not found a way. Did I miss something? -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.