waitfor-postgres

A PostgreSQL resource readiness assertion library built on top of the waitfor framework. This library allows you to wait for PostgreSQL databases to become available before proceeding with your application startup, making it ideal for containerized environments, integration tests, and service orchestration.
Features
- PostgreSQL connectivity testing: Ping PostgreSQL databases to verify they're ready
- Multiple URL schemes: Supports both
postgres:// and postgresql:// connection strings
- Configurable retry logic: Customize attempts, intervals, and timeouts
- Context support: Full context cancellation and timeout support
- Integration ready: Built for Docker Compose, Kubernetes, and CI/CD pipelines
Installation
go get github.com/go-waitfor/waitfor-postgres
Quick Start
package main
import (
"context"
"fmt"
"time"
"github.com/go-waitfor/waitfor"
"github.com/go-waitfor/waitfor-postgres"
)
func main() {
runner := waitfor.New(postgres.Use())
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
err := runner.Test(
ctx,
[]string{"postgres://user:password@localhost/mydb"},
waitfor.WithAttempts(10),
waitfor.WithInterval(2000), // 2000 milliseconds (2 seconds)
)
if err != nil {
fmt.Printf("PostgreSQL not ready: %v\n", err)
return
}
fmt.Println("PostgreSQL is ready!")
}
Usage Examples
Basic Connection Test
runner := waitfor.New(postgres.Use())
err := runner.Test(
context.Background(),
[]string{"postgres://localhost/mydb"},
)
Multiple Databases
databases := []string{
"postgres://user:pass@db1:5432/app_db",
"postgresql://user:pass@db2:5432/cache_db",
}
err := runner.Test(context.Background(), databases)
Custom Configuration
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
err := runner.Test(
ctx,
[]string{"postgres://user:pass@localhost/mydb"},
waitfor.WithAttempts(20), // Try up to 20 times
waitfor.WithInterval(5000), // Wait 5000 milliseconds (5 seconds) between attempts
)
Error Handling
err := runner.Test(ctx, []string{"postgres://localhost/mydb"})
if err != nil {
// Handle different types of errors
fmt.Printf("Database connection failed: %v\n", err)
// Check if it's a timeout
if ctx.Err() == context.DeadlineExceeded {
fmt.Println("Timed out waiting for database")
}
}
The library supports both PostgreSQL URL schemes:
postgres://user:password@host:port/dbname?sslmode=disable
postgresql://user:password@host:port/dbname?sslmode=require
URL Components
postgresql://username:password@hostname:port/database?param1=value1¶m2=value2
- username: Database username (optional)
- password: Database password (optional)
- hostname: Database server hostname or IP
- port: Database server port (default: 5432)
- database: Database name (optional)
- parameters: Connection parameters like
sslmode, connect_timeout, etc.
Configuration Options
The library uses the waitfor framework's configuration options:
| Option |
Description |
Default |
WithAttempts(n) |
Maximum number of connection attempts |
30 |
WithInterval(ms) |
Time between connection attempts in milliseconds |
1000 (1 second) |
Context and Timeouts
Always use context with timeouts for production applications:
// Set overall timeout for the entire wait operation
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()
// The Test method will respect the context deadline
err := runner.Test(ctx, []string{"postgres://localhost/mydb"}, waitfor.WithAttempts(20))
if errors.Is(err, context.DeadlineExceeded) {
log.Fatal("Timed out waiting for PostgreSQL to become ready")
}
Integration Examples
Docker Compose
version: '3.8'
services:
postgres:
image: postgres:15
environment:
POSTGRES_DB: myapp
POSTGRES_USER: user
POSTGRES_PASSWORD: password
app:
build: .
depends_on:
- postgres
environment:
DATABASE_URL: postgres://user:password@postgres:5432/myapp
Kubernetes Init Container
initContainers:
- name: wait-for-db
image: my-app:latest
command: ["/wait-for-postgres"]
env:
- name: DATABASE_URL
value: "postgres://user:pass@postgres-service:5432/mydb"
Troubleshooting
Common Connection Issues
- Connection refused: Check if PostgreSQL is running and accessible
- Authentication failed: Verify username and password
- Database not found: Ensure the database exists
- SSL/TLS issues: Check
sslmode parameter in connection string
Debugging Tips
// Enable detailed logging (if using a logger)
log.Printf("Testing connection to: %s", databaseURL)
err := runner.Test(ctx, []string{databaseURL})
if err != nil {
log.Printf("Connection failed: %v", err)
}
License
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.