lib / pq

Pure Go Postgres driver for database/sql
https://pkg.go.dev/github.com/lib/pq
MIT License
9.04k stars 909 forks source link

Tx.Rollback returns ErrBadConn after context is cancelled #1137

Open emersion opened 1 year ago

emersion commented 1 year ago

Sometimes, Tx.Rollback returns ErrBadConn after a context is cancelled. Doesn't happen on context deadline exceeded it seems.

Reproducer with v1.10.9:

package main

import (
    "log"
    "database/sql"
    "context"
    "sync"

    "github.com/lib/pq"
)

var wg sync.WaitGroup

func main() {
    connStr := "dbname=<name> sslmode=disable"
    db, err := sql.Open("postgres", connStr)
    if err != nil {
        log.Fatal(err)
    }
    db.SetMaxOpenConns(5)

    for i := 0; i < 10000; i++ {
        wg.Add(1)
        go run(db)
    }

    wg.Wait()
}

func run(db *sql.DB) {
    ctx := context.Background()

    ctx, cancel := context.WithCancel(ctx)

    tx, err := db.BeginTx(ctx, &sql.TxOptions{
        ReadOnly:  true,
    })
    if err != nil {
        log.Fatal("BeginTx: ", err)
    }

    cancel()

    ids := []int{1}
    _, err1 := tx.ExecContext(ctx, `SELECT * FROM "user" WHERE id = ANY($1)`, pq.Array(ids))

    err2 := tx.Rollback()

    if err2 != nil {
        log.Print("err1 = ", err1)
        log.Print("err2 = ", err2)
    }

    wg.Done()
}

Output is repeated patterns like the following:

2023/08/16 19:59:38 err1 = context canceled
2023/08/16 19:59:38 err2 = driver: bad connection