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, max: 4)
pool.start!

# 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)



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

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

Instance Method Details

#dumpObject

Convert internal state into text.



73
74
75
76
77
78
79
# File 'lib/pgtk/retry.rb', line 73

def dump
  [
    @pool.dump,
    '',
    "Pgtk::Retry (attempts=#{@attempts})"
  ].join("\n")
end

#exec(sql) ⇒ Array

Execute a SQL query with automatic retry for SELECT queries.

Parameters:

  • sql (String)

    The SQL query with params inside (possibly)

Returns:

  • (Array)

    Result rows



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/pgtk/retry.rb', line 85

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

#start!Object

Start a new connection pool with the given arguments.



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

def start!
  @pool.start!
end

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

Run a transaction without retry logic.

Yields:

  • (Object)

    Yields the transaction object

Returns:

  • (Object)

    Result of the block



105
106
107
# File 'lib/pgtk/retry.rb', line 105

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

#versionString

Get the version of PostgreSQL server.

Returns:

  • (String)

    Version of PostgreSQL server



68
69
70
# File 'lib/pgtk/retry.rb', line 68

def version
  @pool.version
end