Class: Pgtk::Retry

Inherits:
Object
  • Object
show all
Defined in:
lib/pgtk/retry.rb

Overview

Retry is a decorator for Pool that automatically retries failed SELECT queries. It provides fault tolerance for transient database errors by retrying read-only operations a configurable number of times before giving up.

This class implements the same interface as Pool but adds retry logic specifically for SELECT queries. Non-SELECT queries are executed without retry to maintain data integrity and avoid unintended side effects from duplicate writes.

Basic usage:

# Create and configure a regular pool
pool = Pgtk::Pool.new(wire).start(4)

# Wrap the pool in a retry decorator with 3 attempts
retry_pool = Pgtk::Retry.new(pool, attempts: 3)

# SELECT queries are automatically retried on failure
begin
  retry_pool.exec('SELECT * FROM users WHERE id = $1', [42])
rescue PG::Error => e
  puts "Query failed after 3 attempts: #{e.message}"
end

# Non-SELECT queries are not retried
retry_pool.exec('UPDATE users SET active = true WHERE id = $1', [42])

# Transactions pass through without retry logic
retry_pool.transaction do |t|
  t.exec('SELECT * FROM accounts')  # No retry within transaction
  t.exec('UPDATE accounts SET balance = balance + 100')
end

# Combining with other decorators
impatient = Pgtk::Impatient.new(retry_pool, 5)
spy = Pgtk::Spy.new(impatient) do |sql, duration|
  puts "Query: #{sql} (#{duration}s)"
end
Author

Yegor Bugayenko ([email protected])

Copyright

Copyright © 2019-2025 Yegor Bugayenko

License

MIT

Instance Method Summary collapse

Constructor Details

#initialize(pool, attempts: 3) ⇒ Retry

Constructor.

Parameters:

  • pool (Pgtk::Pool)

    The pool to decorate

  • attempts (Integer) (defaults to: 3)

    Number of attempts to make (default: 3)



54
55
56
57
# File 'lib/pgtk/retry.rb', line 54

def initialize(pool, attempts: 3)
  @pool = pool
  @attempts = attempts
end

Instance Method Details

#exec(sql, *args) ⇒ Array

Execute a SQL query with automatic retry for SELECT queries.

Parameters:

  • sql (String)

    The SQL query with params inside (possibly)

  • args (Array)

    List of arguments

Returns:

  • (Array)

    Result rows



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/pgtk/retry.rb', line 71

def exec(sql, *args)
  query = sql.is_a?(Array) ? sql.join(' ') : sql
  if query.strip.upcase.start_with?('SELECT')
    attempt = 0
    begin
      @pool.exec(sql, *args)
    rescue StandardError => e
      attempt += 1
      raise e if attempt >= @attempts
      retry
    end
  else
    @pool.exec(sql, *args)
  end
end

#transaction {|Object| ... } ⇒ Object

Run a transaction without retry logic.

Yields:

  • (Object)

    Yields the transaction object

Returns:

  • (Object)

    Result of the block



91
92
93
# File 'lib/pgtk/retry.rb', line 91

def transaction(&block)
  @pool.transaction(&block)
end

#versionString

Get the version of PostgreSQL server.

Returns:

  • (String)

    Version of PostgreSQL server



62
63
64
# File 'lib/pgtk/retry.rb', line 62

def version
  @pool.version
end