用ActiveRecord连接池问题鲁弗斯调度对象(Connection pool issue wi

2019-06-25 21:12发布

我使用的是鲁弗斯调度运行一个数字,做一些不同的任务与ActiveRecord对象频繁跳槽的。 如果有任何形式的网络或PostgreSQL打嗝,即使恢复后,所有的线程会抛出下面的错误,直到进程重新启动:

的ActiveRecord :: ConnectionTimeoutError(无法获得5秒内数据库连接(等待5.000122687秒)最大池大小是目前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

Answer 1:

鲁弗斯调度开始每一项工作一个新的线程。 ActiveRecord的,另一方面不能共享线程之间的连接,所以它需要分配给特定线程的连接。

当你的线程没有连线,它会得到一个从池中。 (如果池中的所有连接都在使用,它会等待,直到一个是从另一个线程返回。最终超时和投掷ConnectionTimeoutError)

这是你的责任,将其返回到池中,当你用它做,在一个Rails应用程序,这是自动完成的。 但是,如果你正在管理自己的线程(如鲁弗斯那样),则必须将此自己做。

Lucklily,对于这样的一个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



Answer 2:

其原因可能是,你有哪些正在使用的所有连接多个线程,如果DataFeed.update方法需要超过5秒,比你的块可以重叠。

尝试

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

也可以尝试释放连接,而不是关闭它。

 ActiveRecord::Base.connection_pool.release_connection


Answer 3:

我真的不知道鲁弗斯调度,但我得到了一些想法。

第一个问题可能是对鲁弗斯调度不正确检出数据库连接的错误。 如果是这种情况的唯一解决办法是手动清除陈旧的连接,你已经做的,并告知鲁弗斯调度的作者您的问题。

可能发生的另一个问题是,你的数据传送专线操作需要很长的时间,因为它是每5个secondes Rails的已经不多了数据库连接进行的,但它是相当不可能的。



文章来源: Connection pool issue with ActiveRecord objects in rufus-scheduler