class Sidekiq::PgHelpers::Middleware::ConnectionRecovery

Helps keep ActiveRecord’s connection pool healthy by detecting common Postgres errors

Constants

PG_CONNECTION_ERRORS

Attributes

reconnection_attempts[RW]

Public Class Methods

new() click to toggle source
# File lib/sidekiq/pg_helpers/middleware/connection_recovery.rb, line 9
def initialize
  @reconnection_attempts = 0
end

Public Instance Methods

call(*) { || ... } click to toggle source

Detects commons problems with Postgres connections and forces ActiveRecord to close and re-open the offending connection, then automatically retries the error

# File lib/sidekiq/pg_helpers/middleware/connection_recovery.rb, line 15
def call(*)
  yield
rescue *PG_CONNECTION_ERRORS => e
  clean_up_connection(e)
  retry
rescue ActiveRecord::StatementInvalid => e
  raise unless PG_CONNECTION_ERRORS.include?(e.original_exception.class)
  clean_up_connection(e)
  retry
end

Private Instance Methods

clean_up_connection(e) click to toggle source
# File lib/sidekiq/pg_helpers/middleware/connection_recovery.rb, line 28
def clean_up_connection(e)
  if reconnection_attempts >= 4
    Sidekiq.logger.error "Unable to re-establish Postgres connection after five attempts, giving up"
    raise
  end

  Sidekiq.logger.warn "Received #{e.class}, disconnecting and cleaning up our Postgres connection before re-trying"

  # Probably due to an abrupt disconnection: https://devcenter.heroku.com/articles/postgres-logs-errors#pgerror-ssl-syscall-error-eof-detected
  # The next time we access an ActiveRecord connection, it should automatically check out a fresh connection to replace this one
  connection = ActiveRecord::Base.connection
  connection.disconnect!
  ActiveRecord::Base.connection_pool.remove(connection)

  # Ensure we get a fresh connection the next time we access an activerecord object
  ActiveRecord::Base.clear_active_connections!

  self.reconnection_attempts = reconnection_attempts + 1
end