Closed egonelbre closed 3 weeks ago
Here's a reproducer:
package main
import (
"context"
"database/sql"
"fmt"
"time"
_ "github.com/googleapis/go-sql-spanner"
"github.com/googleapis/go-sql-spanner/examples"
)
// Simple sample application that shows how to use the Spanner Go sql driver.
//
// Execute the sample with the command `go run main.go` from this directory.
func helloWorld(projectId, instanceId, databaseId string) error {
ctx := context.Background()
db, err := sql.Open("spanner", fmt.Sprintf("projects/%s/instances/%s/databases/%s", projectId, instanceId, databaseId))
if err != nil {
return fmt.Errorf("failed to open database connection: %v\n", err)
}
defer db.Close()
go func() {
time.Sleep(time.Second)
db.Close()
}()
for {
rows, err := db.QueryContext(ctx, "SELECT 'Hello World!'")
if err != nil {
return fmt.Errorf("failed to execute query: %v", err)
}
var msg string
for rows.Next() {
if err := rows.Scan(&msg); err != nil {
return fmt.Errorf("failed to scan row values: %v", err)
}
fmt.Printf("%s\n", msg)
}
if err := rows.Err(); err != nil {
return fmt.Errorf("failed to execute query: %v", err)
}
if err := rows.Close(); err != nil {
fmt.Printf("failed to close rows: %v", err)
return nil
}
}
}
func main() {
examples.RunSampleOnEmulator(helloWorld)
}
I currently haven't yet diagnosed the underlying issue, but there's a possible to get a data race while the database is shutting down.
Based on the stack traces I would guess it has to do with having ongoing operations while calling
*sql.DB.Close
. https://pkg.go.dev/database/sql#Conn.Close can be called concurrently with any other pending operations.I'll try to create a reproducer next week.
Race 1:
Race 2: