Should context cancelation be handled in application code or by row.Scan/row.Next
#2435
-
|
I'm currently looking into creating an iterator, stream based, approach of consuming rows at sqlc-dev/sqlc#720 (comment). When the context provided to Example code: package main
import (
"context"
"log"
"github.com/jackc/pgx/v5"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
conn, err := pgx.Connect(ctx, `connstring`) // Same behavior if this were background context
if err != nil {
log.Fatalf("Unable to connect to database: %v", err)
}
defer conn.Close(context.Background())
rows, err := conn.Query(ctx, `SELECT generate_series(1, 10) AS row_number`)
if err != nil {
log.Fatalf("Query failed: %v", err)
}
defer rows.Close()
for rows.Next() {
// Why do we need to do this and does pgx not handle this?
select {
case <-ctx.Done():
break
default:
}
var id int
err := rows.Scan(&id)
if err != nil {
log.Fatalf("Scan failed: %v", err)
}
log.Printf("Row returned: %d\n", id)
// Simulate cancel by e.g. CTRL+C or some other timeout.
// Expecting row.Next to return false or row.Scan to error on next call.
cancel()
}
if err := rows.Err(); err != nil {
log.Fatalf("error: %v", err)
}
}I had assumed
|
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 2 replies
-
Context is used to cancel potentially long running or blocking operations. Neither |
Beta Was this translation helpful? Give feedback.
Context is used to cancel potentially long running or blocking operations. Neither
Rows.Next()norRows.Scan()are either. The context will block any further network reads. Presumably, the rows have already been read over the wire. If you were to change yourgenerate_seriesquery to something that returned so many rows that pgx had to read from the network multiple times then you would get aRows.Next() => false.