【问题标题】:Connection pool issue with ActiveRecord objects in rufus-schedulerrufus-scheduler 中 ActiveRecord 对象的连接池问题
【发布时间】:2012-06-30 05:15:29
【问题描述】:

我正在使用 rufus-scheduler 运行一些频繁的作业,这些作业使用 ActiveRecord 对象执行一些不同的任务。如果出现任何类型的网络或 postgresql 打嗝,即使在恢复后,所有线程都会抛出以下错误,直到进程重新启动:

ActiveRecord::ConnectionTimeoutError (could not get a database connection within 5 seconds (waited 5.000122687 seconds). 最大池大小当前为 5;考虑增加它。

重新启动 postgres 可以很容易地重现该错误。我试过玩(最多 15 个)池大小,但没有运气。

这让我相信连接只是处于陈旧状态,我认为可以通过调用 clear_stale_cached_connections! 来修复。

有没有更可靠的模式来做到这一点?

传递的块是一个简单的选择和更新活动记录调用,并且恰好与 AR 对象是什么有关。

鲁弗斯工作:

scheduler.every '5s' do
  db do
    DataFeed.update  #standard AR select/update
  end
end

包装器:

  def db(&block)
    begin
      ActiveRecord::Base.connection_pool.clear_stale_cached_connections!
      #ActiveRecord::Base.establish_connection    # this didn't help either way
      yield block
    rescue Exception => e
      raise e
    ensure
      ActiveRecord::Base.connection.close if ActiveRecord::Base.connection
      ActiveRecord::Base.clear_active_connections!
    end
  end

【问题讨论】:

  • 我也面临同样的问题,在上面尝试过,甚至ActiveRecord::Base.connection_pool.with_connection 做但不工作

标签: ruby-on-rails activerecord rufus-scheduler


【解决方案1】:

Rufus 调度程序为每个作业启动一个新线程。 另一方面,ActiveRecord 不能在线程之间共享连接,因此它需要将连接分配给特定的线程。

当您的线程还没有连接时,它将从池中获取一个。 (如果池中的所有连接都在使用中,它会等到另一个线程返回一个。最终超时并抛出ConnectionTimeoutError)

您有责任在完成后将其返回到池中,在 Rails 应用程序中,这是自动完成的。但是,如果您要管理自己的线程(如 rufus 那样),则必须自己执行此操作。

幸运的是,有一个用于此的 api: 如果您将代码放在 with_connection 块中,它将从池中获取连接,并在完成后释放它

ActiveRecord::Base.connection_pool.with_connection do
  #your code here
end

在你的情况下:

def db
  ActiveRecord::Base.connection_pool.with_connection do
    yield
  end
end

应该做的伎俩....

http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/ConnectionPool.html#method-i-with_connection

【讨论】:

  • 也适用于 Sneakers 或其他可能使用 ActiveRecord 的长时间运行的后台作业进程。在我们重新启动我们的一个数据库服务器后,我收到“PG::UnableToSend: no connection to the server”,认为使用 ActiveRecord 的所有内容都会自动重新连接!这个技巧似乎解决了它。相关问题:github.com/rails/rails/issues/38324
【解决方案2】:

原因可能是您有许多线程正在使用所有连接,如果DataFeed.update 方法花费的时间超过 5 秒,那么您的块可能会被重叠。

试试

scheduler.every("5s",  :allow_overlapping => false) do
#...
end

同时尝试释放连接而不是关闭它。

 ActiveRecord::Base.connection_pool.release_connection

【讨论】:

    【解决方案3】:

    我不太了解 rufus-scheduler,但我有一些想法。

    第一个问题可能是 rufus-scheduler 上的一个错误,它没有正确检查数据库连接。如果是这种情况,唯一的解决方案是像您已经做的那样手动清除陈旧的连接,并将您的问题告知 rufus-scheduler 的作者。

    另一个可能发生的问题是您的 DataFeed 操作需要很长时间,而且因为它每 5 秒执行一次,Rails 的数据库连接已用完,但这不太可能。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-10
      • 2014-12-04
      • 2011-04-01
      相关资源
      最近更新 更多