如何调试陷入db事务的ruby进程?

时间:2018-03-21 23:58:33

标签: ruby-on-rails ruby postgresql sidekiq pg

我在一个相当大的rails应用程序中运行了一些ruby后台处理。后台处理由sidekiq gem执行。我经常会遇到一种非常奇怪的行为,这种行为会导致死亡螺旋式上升。

在连接的postgresql数据库中对单个记录执行简单UPDATE的一些相对简单的作业从来都不会成功。他们执行的查询在postgresql中停留为waiting,在事务中空闲,因为更新查询的事务显然从不发送COMMIT。虽然postgresql正在等待这个,但似乎是ruby后台处理发送了查询! ruby进程似乎在等待事务从postgresql完成,因此没有做任何进一步的工作。

现在我的问题是,在这种僵局的情况下,我该如何进一步调试问题的根本原因? (ruby,postgresql,OS,网络,别的东西)

PS。如果我通过发送SELECT pg_cancel_backend(faulty_pid)手动取消postgresql中的挂起事务,那么挂起的sidekiq / ruby​​进程会立即出现连接错误并恢复正常,继续接收作业并且工作就像什么都没发生一样。这似乎向我表明,db和ruby之间的连接仍然没问题,并且ruby进程并没有真正被卡住。但不知何故出了问题。

PS。我正在运行ruby 2.4.0,rails 4.2,Postgresql 9.3,sidekiq 4.2和pg 0.20.0

1 个答案:

答案 0 :(得分:0)

这可能与你的工作人员打开的postgres有关,这些工作永远不会被关闭。如果你的工作重试,这就解决了这个问题。要解决此问题,您可能希望按计划运行这样的工作程序以清除任何未关闭的连接:

class DbIdleCleanerWorker
  include Sidekiq::Worker

  sidekiq_options retry: 0

  def perform()
    sql = "SELECT pg_terminate_backend(pid)
    FROM pg_stat_activity
    WHERE query != '<IDLE>' AND query NOT ILIKE '%pg_stat_activity%' AND state = 'idle'
      AND now()-pg_stat_activity.query_start > interval '1 minutes'
    ORDER BY query_start desc;"
    ActiveRecord::Base.connection.execute(sql)
  end
end