Correct way to use sql connection with http and pq

548 views
Skip to first unread message

Chris Baynes

unread,
Apr 17, 2013, 6:39:42 AM4/17/13
to golan...@googlegroups.com
The documentation states that the sql.DB returned from Open is "safe for concurrent use by multiple goroutines". In practise we are getting the error "pq: unexpected describe rows response: '\x01'" when running a http server with a global db connection, and testing with concurrent requests.

We're not sure whether this is a misunderstanding of how we should be using the pooled db connection within a http request, or a bug in the pq or database/sql package.

Here's a sample server which fails under those circumstances:

package main

import (
"database/sql"
"fmt"
"net/http"
)

var dbConn *sql.DB

func dbConnect() *sql.DB {
db, err := sql.Open("postgres", "user=dev dbname=my_db sslmode=disable port=5432 host=localhost password=")
if err != nil {
panic(err)
}
return db
}

func main() {
dbConn = dbConnect()
http.HandleFunc("/", run)
http.ListenAndServe(":8080", nil)
}

func run(http.ResponseWriter, *http.Request) {
var pid int
res := dbConn.QueryRow(`SELECT id FROM users WHERE id=$1`, 1365)
err := res.Scan(&pid)
if err != nil {
fmt.Println(err)
return
}
}

Kamil Kisiel

unread,
Apr 17, 2013, 9:31:05 AM4/17/13
to golan...@googlegroups.com
What version of Go are you using? If 1.0.3, do you get the same error with tip?

Chris Baynes

unread,
Apr 17, 2013, 9:37:44 AM4/17/13
to golan...@googlegroups.com
I'm using go tip (the error is reproduced on versions: +d58997478ec6, +9bb42a7021c9).

Mike Hughes

unread,
Apr 17, 2013, 11:40:11 AM4/17/13
to golan...@googlegroups.com
One quick thing before I go to sleep :-)

I noticed you aren't closing the db connection. You may be hitting a limit on the pgsql side.

try adding

defer db.Close()

after

dbConn = dbConnect()

in main.

but, as I said, i'm tired and that may have nothing to do with it :-)

Chris Baynes

unread,
Apr 17, 2013, 12:51:56 PM4/17/13
to golan...@googlegroups.com
I missed the defer close in the code above that's true. But unfortunately that's not the problem, I can reproduce the error with only 5 requests in parallel (my db max connections is at 100).

Another interesting thing is that I cannot reproduce this without the http server - using a loop of goroutines within main to call QueryRow works perfectly without errors. My understanding is that net/http just starts a new goroutine for each new request. Is there some other magic there which could be breaking things?

Kamil Kisiel

unread,
Apr 17, 2013, 12:57:26 PM4/17/13
to golan...@googlegroups.com
Are you able to reproduce it in the goroutine case with GOMAXPROCS > 1 ? Perhaps the way the goroutines are being scheduled is different in your contrived case versus when net/http is used.

Chris Baynes

unread,
Apr 17, 2013, 4:14:38 PM4/17/13
to golan...@googlegroups.com
I've tried it with GOMAXPROCS=4 and the following code, but there is no error produced:

for j := 0; j < 50; j++ {
go func() {
var uid int
res := dbConn.QueryRow(`SELECT id FROM users WHERE id=$1`, 1365)
err := res.Scan(&uid)
if err != nil {
fmt.Println(err)
return
}
}()
}

Alexey Borzenkov

unread,
Apr 17, 2013, 4:33:28 PM4/17/13
to Chris Baynes, golang-nuts
Are you sure you're using latest tip? A bug that would cause your exact behavior was fixed very recently:


Best regards,
Alexey.


--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Chris Baynes

unread,
Apr 18, 2013, 4:32:54 AM4/18/13
to golan...@googlegroups.com, Chris Baynes
Alexey, you were right, this is now working perfectly in the latest go tip! My tip version was a couple of days before the fix. 

Thanks for the help.
Chris
Reply all
Reply to author
Forward
0 new messages