ConnectToPostgres takes in the migration command to run on the database once it connects. To avoid running migrations, pass in `nil` or a no-op function. Regardless of the passed in migration function, if the database is not fully migrated, an error will be returned. This can happen if the database
(ctx context.Context, logger slog.Logger, driver string, dbURL string, migrate func(db *sql.DB) error, opts ...PostgresConnectOption)
| 2592 | // |
| 2593 | // If no error is returned, the database is fully migrated and up to date. |
| 2594 | func ConnectToPostgres(ctx context.Context, logger slog.Logger, driver string, dbURL string, migrate func(db *sql.DB) error, opts ...PostgresConnectOption) (*sql.DB, error) { |
| 2595 | // Apply defaults. |
| 2596 | options := PostgresConnectOptions{ |
| 2597 | MaxOpenConns: 10, |
| 2598 | MaxIdleConns: 3, |
| 2599 | } |
| 2600 | for _, opt := range opts { |
| 2601 | opt(&options) |
| 2602 | } |
| 2603 | logger.Debug(ctx, "connecting to postgresql") |
| 2604 | |
| 2605 | var err error |
| 2606 | var sqlDB *sql.DB |
| 2607 | dbNeedsClosing := true |
| 2608 | // nolint:gocritic // Try to connect for 30 seconds. |
| 2609 | ctx, cancel := context.WithTimeout(ctx, 30*time.Second) |
| 2610 | defer cancel() |
| 2611 | |
| 2612 | defer func() { |
| 2613 | if !dbNeedsClosing { |
| 2614 | return |
| 2615 | } |
| 2616 | if sqlDB != nil { |
| 2617 | _ = sqlDB.Close() |
| 2618 | sqlDB = nil |
| 2619 | logger.Debug(ctx, "closed db before returning from ConnectToPostgres") |
| 2620 | } |
| 2621 | }() |
| 2622 | |
| 2623 | var tries int |
| 2624 | for r := retry.New(time.Second, 3*time.Second); r.Wait(ctx); { |
| 2625 | tries++ |
| 2626 | |
| 2627 | sqlDB, err = sql.Open(driver, dbURL) |
| 2628 | if err != nil { |
| 2629 | logger.Warn(ctx, "connect to postgres: retrying", slog.Error(err), slog.F("try", tries)) |
| 2630 | continue |
| 2631 | } |
| 2632 | |
| 2633 | err = pingPostgres(ctx, sqlDB) |
| 2634 | if err != nil { |
| 2635 | logger.Warn(ctx, "ping postgres: retrying", slog.Error(err), slog.F("try", tries)) |
| 2636 | _ = sqlDB.Close() |
| 2637 | sqlDB = nil |
| 2638 | continue |
| 2639 | } |
| 2640 | |
| 2641 | break |
| 2642 | } |
| 2643 | if err == nil { |
| 2644 | err = ctx.Err() |
| 2645 | } |
| 2646 | if err != nil { |
| 2647 | return nil, xerrors.Errorf("unable to connect after %d tries; last error: %w", tries, err) |
| 2648 | } |
| 2649 | |
| 2650 | // Ensure the PostgreSQL version is >=13.0.0! |
| 2651 | version, err := sqlDB.QueryContext(ctx, "SHOW server_version_num;") |