【问题标题】:How to auto reconnect Rails 6 PostgreSQL connection?如何自动重新连接 Rails 6 PostgreSQL 连接?
【发布时间】:2020-11-19 21:23:26
【问题描述】:

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

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

worker 是我使用 rails runner 运行的简单服务类

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

【问题讨论】:

    标签: ruby-on-rails ruby postgresql


    【解决方案1】:

    我为 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)
    

    灵感来自

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-11-27
      • 2017-01-26
      • 2020-07-28
      • 2014-12-03
      • 2010-11-08
      • 2018-04-27
      • 2017-09-18
      • 2011-02-02
      相关资源
      最近更新 更多