package dbutil
import (
"context"
"github.com/jackc/pgconn"
)
func RetrySerialization(ctx context.Context, max int, fn func(context.Context) error) error {
var last error
for i := 0; i < max; i++ {
if err := fn(ctx); err != nil {
last = err
if pgErr, ok := err.(*pgconn.PgError); ok && pgErr.Code == "40001" {
continue
}
return err
}
return nil
}
return last
}
For workloads that run at SERIALIZABLE isolation (or that hit serialization conflicts under load), retries are part of the contract. The important part is to retry only the safe errors (typically SQLSTATE 40001) and to keep the loop bounded so you don’t create runaway contention. I like to wrap the transaction function in a small retry helper that re-runs the unit of work on serialization failures only. In production, I also add jittered backoff to reduce thundering herds when many transactions collide. This approach keeps call sites clean and ensures you don’t accidentally “retry everything”, which can hide real bugs. When you combine this with good observability (attempt count, conflict rate), you can tune the system rather than guessing. It’s one of those boring patterns that saves you during peak load.
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
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 SignupForm
include ActiveModel::Model
include ActiveModel::Attributes
attribute :account_name, :string
attribute :email, :string
Shallow Controller, Deep Params: Form Object Pattern
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.