【问题标题】:How do I debug a ruby process stuck in a db transaction?如何调试卡在 db 事务中的 ruby​​ 进程?
【发布时间】:2018-08-31 06:52:50
【问题描述】:

我在一个相当大的 rails 应用程序中运行了一些 ruby​​ 后台处理。后台处理由 sidekiq gem 执行。有时我会遇到一种非常奇怪的行为,这种行为会旋转成死亡螺旋。

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

我现在的问题是,在这种死锁情况下,我该如何进一步调试问题的根本原因来自哪里? (ruby、postgresql、操作系统、网络等)

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

附言。我正在运行 ruby​​ 2.4.0、rails 4.2、Postgresql 9.3、sidekiq 4.2 和 pg 0.20.0

【问题讨论】:

  • 你能发布一个挂在 postgres 中的代码示例吗?
  • 另外,您能发布您遇到的任何错误吗?
  • @Niels Kristian 你有想过这个吗?

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


【解决方案1】:

这可能是因为您的工作人员打开了与 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

【讨论】:

  • 连接如何永远不会被工作人员关闭?
  • 工人应该在完成后关闭数据库连接,但如果你想明确一点,你可以在最后添加ActiveRecord::Base.connection.close
猜你喜欢
  • 2013-05-07
  • 2021-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多