Skip to content

Tx.Rollback returns ErrBadConn after context is cancelledΒ #1137

@emersion

Description

@emersion

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions