Skip to content

Commit ad8fb08

Browse files
jackcclaude
andcommitted
Use sync.WaitGroup.Go to simplify goroutine spawning
Go 1.25 adds WaitGroup.Go which combines Add(1), go func, and defer Done() into a single method call, eliminating a common source of mismatched Add/Done bugs. Co-Authored-By: Claude Opus 4.6 <[email protected]>
1 parent 3033773 commit ad8fb08

File tree

3 files changed

+24
-37
lines changed

3 files changed

+24
-37
lines changed

conn_test.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -848,9 +848,7 @@ func TestFatalRxError(t *testing.T) {
848848
pgxtest.SkipCockroachDB(t, conn, "Server does not support pg_terminate_backend() (https://github.com/cockroachdb/cockroach/issues/35897)")
849849

850850
var wg sync.WaitGroup
851-
wg.Add(1)
852-
go func() {
853-
defer wg.Done()
851+
wg.Go(func() {
854852
var n int32
855853
var s string
856854
err := conn.QueryRow(context.Background(), "select 1::int4, pg_sleep(10)::varchar").Scan(&n, &s)
@@ -859,7 +857,7 @@ func TestFatalRxError(t *testing.T) {
859857
t.Errorf("Expected QueryRow Scan to return fatal PgError, but instead received %v", err)
860858
return
861859
}
862-
}()
860+
})
863861

864862
otherConn := mustConnectString(t, os.Getenv("PGX_TEST_DATABASE"))
865863
defer otherConn.Close(context.Background())

pgconn/pgconn.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1396,10 +1396,7 @@ func (pgConn *PgConn) CopyFrom(ctx context.Context, r io.Reader, sql string) (Co
13961396
copyErrChan := make(chan error, 1)
13971397
signalMessageChan := pgConn.signalMessage()
13981398
var wg sync.WaitGroup
1399-
wg.Add(1)
1400-
1401-
go func() {
1402-
defer wg.Done()
1399+
wg.Go(func() {
14031400
buf := iobufpool.Get(65536)
14041401
defer iobufpool.Put(buf)
14051402
(*buf)[0] = 'd'
@@ -1431,7 +1428,7 @@ func (pgConn *PgConn) CopyFrom(ctx context.Context, r io.Reader, sql string) (Co
14311428
default:
14321429
}
14331430
}
1434-
}()
1431+
})
14351432

14361433
var pgErr error
14371434
var copyErr error

stdlib/sql_test.go

Lines changed: 20 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -348,34 +348,30 @@ func TestConnConcurrency(t *testing.T) {
348348
errChan := make(chan error, concurrency)
349349

350350
for i := 1; i <= concurrency; i++ {
351-
wg.Add(1)
352-
353-
go func(idx int) {
354-
defer wg.Done()
355-
351+
wg.Go(func() {
356352
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
357353
defer cancel()
358354

359-
str := strconv.Itoa(idx)
360-
duration := time.Duration(idx) * time.Second
361-
_, err := db.ExecContext(ctx, "insert into t values($1)", idx)
355+
str := strconv.Itoa(i)
356+
duration := time.Duration(i) * time.Second
357+
_, err := db.ExecContext(ctx, "insert into t values($1)", i)
362358
if err != nil {
363-
errChan <- fmt.Errorf("insert failed: %d %w", idx, err)
359+
errChan <- fmt.Errorf("insert failed: %d %w", i, err)
364360
return
365361
}
366-
_, err = db.ExecContext(ctx, "update t set str = $1 where id = $2", str, idx)
362+
_, err = db.ExecContext(ctx, "update t set str = $1 where id = $2", str, i)
367363
if err != nil {
368-
errChan <- fmt.Errorf("update 1 failed: %d %w", idx, err)
364+
errChan <- fmt.Errorf("update 1 failed: %d %w", i, err)
369365
return
370366
}
371-
_, err = db.ExecContext(ctx, "update t set dur_str = $1 where id = $2", duration, idx)
367+
_, err = db.ExecContext(ctx, "update t set dur_str = $1 where id = $2", duration, i)
372368
if err != nil {
373-
errChan <- fmt.Errorf("update 2 failed: %d %w", idx, err)
369+
errChan <- fmt.Errorf("update 2 failed: %d %w", i, err)
374370
return
375371
}
376372

377373
errChan <- nil
378-
}(i)
374+
})
379375
}
380376
wg.Wait()
381377
for i := 1; i <= concurrency; i++ {
@@ -384,41 +380,37 @@ func TestConnConcurrency(t *testing.T) {
384380
}
385381

386382
for i := 1; i <= concurrency; i++ {
387-
wg.Add(1)
388-
389-
go func(idx int) {
390-
defer wg.Done()
391-
383+
wg.Go(func() {
392384
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
393385
defer cancel()
394386

395387
var id int
396388
var str string
397389
var duration pgtype.Interval
398-
err := db.QueryRowContext(ctx, "select id,str,dur_str from t where id = $1", idx).Scan(&id, &str, &duration)
390+
err := db.QueryRowContext(ctx, "select id,str,dur_str from t where id = $1", i).Scan(&id, &str, &duration)
399391
if err != nil {
400-
errChan <- fmt.Errorf("select failed: %d %w", idx, err)
392+
errChan <- fmt.Errorf("select failed: %d %w", i, err)
401393
return
402394
}
403-
if id != idx {
404-
errChan <- fmt.Errorf("id mismatch: %d %d", idx, id)
395+
if id != i {
396+
errChan <- fmt.Errorf("id mismatch: %d %d", i, id)
405397
return
406398
}
407-
if str != strconv.Itoa(idx) {
408-
errChan <- fmt.Errorf("str mismatch: %d %s", idx, str)
399+
if str != strconv.Itoa(i) {
400+
errChan <- fmt.Errorf("str mismatch: %d %s", i, str)
409401
return
410402
}
411403
expectedDuration := pgtype.Interval{
412-
Microseconds: int64(idx) * time.Second.Microseconds(),
404+
Microseconds: int64(i) * time.Second.Microseconds(),
413405
Valid: true,
414406
}
415407
if duration != expectedDuration {
416-
errChan <- fmt.Errorf("duration mismatch: %d %v", idx, duration)
408+
errChan <- fmt.Errorf("duration mismatch: %d %v", i, duration)
417409
return
418410
}
419411

420412
errChan <- nil
421-
}(i)
413+
})
422414
}
423415
wg.Wait()
424416
for i := 1; i <= concurrency; i++ {

0 commit comments

Comments
 (0)