How to Use Connection Retry and Circuit Breaker for Databases in Go
Go's standard library does not include built-in connection retry or circuit breaker logic for databases; you must implement these patterns manually or use a third-party library. For a basic retry mechanism, wrap your database call in a loop with exponential backoff to handle transient failures. For a circuit breaker, track failure counts and stop attempting connections after a threshold is reached to prevent cascading failures.
package main
import (
"context"
"database/sql"
"fmt"
"time"
_ "github.com/lib/pq"
)
func connectWithRetry(ctx context.Context, dsn string, maxRetries int) (*sql.DB, error) {
var db *sql.DB
var err error
for i := 0; i < maxRetries; i++ {
db, err = sql.Open("postgres", dsn)
if err == nil {
if err = db.PingContext(ctx); err == nil {
return db, nil
}
// Close the DB if Ping fails to avoid leaking connections
db.Close()
}
time.Sleep(time.Duration(i+1) * time.Second)
}
return nil, fmt.Errorf("failed to connect after %d retries: %w", maxRetries, err)
}
func main() {
ctx := context.Background()
dsn := "host=localhost user=postgres password=secret dbname=test sslmode=disable"
db, err := connectWithRetry(ctx, dsn, 5)
if err != nil {
fmt.Println("Error:", err)
return
}
defer db.Close()
fmt.Println("Connected successfully")
}
To implement a circuit breaker, maintain a state (closed, open, half-open) and a failure counter. If the counter exceeds a limit, switch to the "open" state and reject new requests immediately. After a timeout, switch to "half-open" to test the connection; if it succeeds, reset to "closed".