如何自动重新连接 Rails 6 PostgreSQL 连接?

问题描述 投票:0回答:2

我有一个带有一些工作进程的 Rails 6 应用程序。该应用程序使用 PostgreSQL 作为数据库。有时数据库会重新启动(例如次要版本升级)并且工作人员会失去连接。我希望它们能够自动重新连接,但它没有发生。

我尝试在database.yml中使用

reconnect: true
标志。同样的故事。我仍然收到
PG::UnableToSend: no connection to the server
。该选项甚至在 PostgresqlAdapter 中不可用。我猜这只是 MySQL 适配器选项。

工人是我运行的简单服务类

rails runner

可以做什么?我相信答案一定很简单。

ruby-on-rails ruby postgresql
2个回答
9
投票

我为PG自动重连做了一个ActiveRecord补丁。

处理异常可以优化,但我有一些奇怪的

PG::UnableToSend
PG::ConnectionBad
PG::Error
的混合,所以我改为比较异常名称。

module PostgreSQLAdapterAutoReconnectPatch
  QUERY_EXCEPTIONS = [
    "SSL connection has been closed unexpectedly",
    "server closed the connection unexpectedly",
    "no connection to the server",
  ].freeze

  CONNECTION_EXCEPTIONS = [
    "could not connect to server",
    "the database system is starting up",
  ].freeze

  def exec_query(*args)
    super(*args)
  rescue ActiveRecord::StatementInvalid => e
    raise unless recoverable_query?(e.message)

    in_transaction = transaction_manager.current_transaction.open?
    try_reconnect
    in_transaction ? raise : retry
  end

  private

  def recoverable_query?(error_message)
    QUERY_EXCEPTIONS.any? { |e| error_message.include?(e) }
  end

  def recoverable_connection?(error_message)
    CONNECTION_EXCEPTIONS.any? { |e| error_message.include?(e) }
  end

  def try_reconnect
    sleep_times = [0.1, 0.5, 1, 2, 4, 8, 16, 32]

    begin
      reconnect!
    rescue PG::Error => e
      sleep_time = sleep_times.shift
      if sleep_time && recoverable_connection?(e.message)
        logger.warn("DB Server timed out, retrying in #{sleep_time} sec")
        sleep sleep_time
        retry
      else
        logger.error(e)
        raise
      end
    end
  end
end

require "active_record/connection_adapters/postgresql_adapter"
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.prepend(PostgreSQLAdapterAutoReconnectPatch)

灵感来自


0
投票

对@AlexeySchepin 的回答稍加即兴创作。

@CareunoMerchan - 这修复了“(参数数量错误(给定 4 个,预期 1..3):config/initializers/postgresql_auto_reconnect.rb:14:in `exec_query'”错误

在调用 super 方法时包含 ** 双 splat 运算符

源代码参考:https://github.com/rails/rails/blob/94b5cd3a20edadd6f6b8cf0bdf1a4d4919df86cb/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb#L80

module PSQLAutoReconnectPatch
  QUERY_EXCEPTIONS = [
    "SSL connection has been closed unexpectedly",
    "server closed the connection unexpectedly",
    "no connection to the server",
  ].freeze

  CONNECTION_EXCEPTIONS = [
    "could not connect to server",
    "the database system is starting up",
  ].freeze

  def exec_query(*args, **params)
    super(*args, **params)
  rescue ActiveRecord::StatementInvalid => e
    raise unless recoverable_query?(e.message)

    in_transaction = transaction_manager.current_transaction.open?
    try_reconnect
    in_transaction ? raise : retry
  end

  private

  def recoverable_query?(error_message)
    QUERY_EXCEPTIONS.any? { |e| error_message.include?(e) }
  end

  def recoverable_connection?(error_message)
    CONNECTION_EXCEPTIONS.any? { |e| error_message.include?(e) }
  end

  def try_reconnect
    sleep_times = [0.1, 0.5, 1]

    begin
      reconnect!
    rescue PG::Error => e
      sleep_time = sleep_times.shift
      if sleep_time && recoverable_connection?(e.message)
        Rails.logger.error("DB Server timed out, retrying in #{sleep_time} sec")
        sleep sleep_time
        retry
      else
        Rails.logger.error(e)
        raise
      end
    end
  end
end

require "active_record/connection_adapters/postgresql_adapter"
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.prepend(PSQLAutoReconnectPatch)
© www.soinside.com 2019 - 2024. All rights reserved.