Describe the bug
I spend quite some time further debugging #2551, and think that I now found the actual issue I was running into.
When the context is canceled while a transaction query is executed, the low-level pgconn.PgConn is closed due to an i/o timeout at
|
msg, err := mrr.pgConn.receiveMessage() |
|
if err != nil { |
|
mrr.pgConn.contextWatcher.Unwatch() |
|
mrr.err = normalizeTimeoutError(mrr.ctx, err) |
|
mrr.closed = true |
|
mrr.pgConn.asyncClose() |
|
return nil, mrr.err |
But the outer
pgx.dbTx state is not set to "closed".
To Reproduce
Steps to reproduce the behavior:
package main
import (
"context"
"fmt"
"os"
"time"
"github.com/jackc/pgx/v5"
)
func main() {
dsn := os.Getenv("TEST_DATABASE_POSTGRESQL")
conn, err := pgx.Connect(context.Background(), dsn)
if err != nil {
fmt.Printf("unexpected error: %v\n", err)
os.Exit(1)
}
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
tx, err := conn.BeginTx(ctx, pgx.TxOptions{})
if err != nil {
fmt.Printf("unexpected error: %v\n", err)
os.Exit(1)
}
// Sleep for longer than the context timeout to trigger a cancellation
_, _ = tx.Exec(ctx, "SELECT pg_sleep(1)")
err = tx.Rollback(context.Background())
fmt.Printf("error on first rollback: %v\n", err)
err = tx.Rollback(context.Background())
fmt.Printf("error on second rollback: %v\n", err)
}
// outputs:
// error on first rollback: conn closed
// error on second rollback: tx is closed
Expected behavior
The transaction state should match the underlying connection state, or rather the error returned from tx.Rollback should be pgx.ErrTxClosed when the connection is closed.
It generally seems weird to me that the low-level connection would close itself without notifying the higher-level code that created the connection.
Actual behavior
An unexpected, non-assertable, low-level error is returned.
Version
- Go:
$ go version -> go version go1.26.2 darwin/arm64
- PostgreSQL:
$ psql --no-psqlrc --tuples-only -c 'select version()' -> PostgreSQL 16.13 (Debian 16.13-1.pgdg13+1) on aarch64-unknown-linux-gnu, compiled by gcc (Debian 14.2.0-19) 14.2.0, 64-bit
- pgx:
$ grep 'github.com/jackc/pgx/v[0-9]' go.mod -> v5.9.2
Additional context
Potentially related: #1145 #2100
Describe the bug
I spend quite some time further debugging #2551, and think that I now found the actual issue I was running into.
When the context is canceled while a transaction query is executed, the low-level
pgconn.PgConnis closed due to ani/o timeoutatpgx/pgconn/pgconn.go
Lines 1533 to 1539 in 82b212c
But the outer
pgx.dbTxstate is not set to "closed".To Reproduce
Steps to reproduce the behavior:
Expected behavior
The transaction state should match the underlying connection state, or rather the error returned from
tx.Rollbackshould bepgx.ErrTxClosedwhen the connection is closed.It generally seems weird to me that the low-level connection would close itself without notifying the higher-level code that created the connection.
Actual behavior
An unexpected, non-assertable, low-level error is returned.
Version
$ go version-> go version go1.26.2 darwin/arm64$ psql --no-psqlrc --tuples-only -c 'select version()'-> PostgreSQL 16.13 (Debian 16.13-1.pgdg13+1) on aarch64-unknown-linux-gnu, compiled by gcc (Debian 14.2.0-19) 14.2.0, 64-bit$ grep 'github.com/jackc/pgx/v[0-9]' go.mod-> v5.9.2Additional context
Potentially related: #1145 #2100