package migrate
import (
"context"
"github.com/jackc/pgx/v5/pgxpool"
)
func WithAdvisoryLock(ctx context.Context, db *pgxpool.Pool, lockID int64, fn func(context.Context) error) error {
var got bool
if err := db.QueryRow(ctx, `SELECT pg_try_advisory_lock($1)`, lockID).Scan(&got); err != nil {
return err
}
if !got {
return nil
}
defer db.Exec(ctx, `SELECT pg_advisory_unlock($1)`, lockID)
return fn(ctx)
}
I generally prefer running migrations in a separate release step, but for smaller deployments it’s sometimes pragmatic to run them at startup. The failure mode to avoid is “every instance runs migrations at once.” The pattern here uses Postgres advisory locks: only one instance can hold the lock, so only one instance performs migrations. Everyone else waits (or skips) and then continues booting. This keeps startup safe during rolling deploys and prevents two migrators from colliding. I still keep migrations idempotent and I make startup fail if migrations fail, because a partially migrated schema is worse than downtime. In production, you’ll want observability around migration duration and a maximum lock wait so the service doesn’t hang forever. But as a baseline, advisory locks make the approach much safer.
Related snips
package api
import (
"net/http"
"runtime/debug"
)
Expose build metadata for debugging deploys
export interface RetryOptions {
retries: number;
baseMs: number;
maxMs: number;
signal?: AbortSignal;
onRetry?: (attempt: number, delay: number, err: unknown) => void;
Exponential backoff with jitter for retries
package dbutil
import (
"context"
"github.com/jackc/pgconn"
Retry Postgres serialization failures with bounded attempts
require "csv"
class PeopleCsvStream
include Enumerable
HEADERS = %w[id full_name email signed_up_at plan].freeze
Resilient CSV Export as a Streamed Response
class AddSettingsToAccounts < ActiveRecord::Migration[7.1]
disable_ddl_transaction!
def change
add_column :accounts, :settings, :jsonb, null: false, default: {}
Postgres JSONB Partial Index for Feature Flags
package files
import (
"context"
"time"
Presigned S3 upload URLs (AWS SDK v2)
Share this code
Here's the card — post it anywhere.