ruby-on-rails – 在rufus-scheduler中使用ActiveRecord对象的连接池问题

前端之家收集整理的这篇文章主要介绍了ruby-on-rails – 在rufus-scheduler中使用ActiveRecord对象的连接池问题前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在使用rufus-scheduler来运行一些频繁的作业,它们通过ActiveRecord对象执行各种任务.如果有任何类型的网络或 postgresql hiccup,即使恢复后,所有线程将抛出以下错误,直到重新启动该过程:

ActiveRecord :: ConnectionTimeoutError(无法在5秒内获取数据库连接(等待5.000122687秒).最大池大小当前为5;请考虑增加它.

通过重新启动postgres可以轻松地复制错误.我已经尝试玩(最多15)与游泳池的大小,但没有运气在那里.

这导致我相信连接只是处于一个陈旧的状态,我认为这将会调用clear_stale_cached_connections!

有更可靠的模式吗?

传递的块是一个简单的选择和更新活动记录调用,恰好是AR对象的重要事件.

rufus工作:

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

解决方法

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

猜你在找的Ruby相关文章