I have run into an interesting issue, namely, that db.Ping() does not return an error even if the database has been killed since the first attempt.
Source code below:
import (
"database/sql"
"fmt"
"log"
"time"
_ "github.com/go-sql-driver/mysql"
)
type database struct {
datasource string
conn *sql.DB
}
// Connect creates and initialises a Database struct
func (db *database) Connect(server, user, password, DBPort string) error {
var err error
db.datasource = fmt.Sprintf("%s:%s@/", user, password)
db.conn, err = sql.Open(server, db.datasource)
if err != nil {
log.Fatal(err)
}
err = db.conn.Ping()
if err != nil {
db.conn.Close()
return err
}
log.Println("Waiting for 15 seconds, kill the DB")
<-time.After(15 * time.Second)
err = db.conn.Ping()
if err != nil {
db.conn.Close()
return err
}
log.Println("Second ping successful")
return nil
}
At first, the database is up, so the first Ping succeeds. However, I put a delay in there just for the sake of testing. In that 15 seconds I stop the database (sudo service mysql stop
), however, db.Ping() still succeeds.
If I were to execute any actual query (via db.Query
, db.QueryRow
or db.Exec
), then the sql package would panic with Broken Pipe (which is expected).
Am I doing something wrong?
also: go version go1.7.1 linux/amd64
Thanks in advance!
Ping, after the first connection, doesn't actually ping the database. It's odd, and wrong, but that's the way it works (until Go 1.8). If there's an existing connection in the connection pool that hasn't timed out, Ping will simply remove it from the pool and return it to you, without actually bothering to check if the database is still there.
Kardianos (who wrote the above linked document, as well as Govendor) fixed this in 1.8, provided the database driver supports it. Until then, however, Ping isn't reliable for determining if the database is still there.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With