ActiveRecord :: Base.connection.update(sql)有时会返回不正确数量的受影响的行

时间:2010-06-29 17:14:55

标签: mysql ruby-on-rails activerecord optimistic-locking

我有一个包含以下环境的制作网站:

  • Rails 2.3.5
  • MySQL Server 5.1.33
  • Enterprise Ruby 1.8.6(2008-08-11 patchlevel 287)[x86_64-linux]
  • mysql gem 2.7
  • 旧版本的BackgrounDRb插件在4个不同的服务器上运行,用于后台任务,每个服务器有5个不同的工作者( Ruby线程,而不是单独的进程!)。

其中一个BackgrounDRb工作人员使用“乐观锁定”的变体处理作业队列:

    update_sql = "update jobs
                  set updated_at = CURRENT_TIMESTAMP,
                      in_process = 1
                  where id = #{job.id} and in_process = 0"

    affected_rows = Job.connection.update(update_sql)
    captured_job = affected_rows > 0 ? Job.find(job.id) : nil

上面的代码尝试使用给定的ID和in_process字段的额外条件更新记录。因此,如果同一记录已由不同的服务器/进程更新,则UPDATE语句将返回0(零),并且不会由2个不同的服务器同时处理该作业。

问题是:有时“Job.connection.update(update_sql)”返回0(零),即使记录实际更新了!在重度日志记录添加到代码后,我才能找到它。它只发生在夜间生产中,当我们负载很重时......

我的猜测是mysql gem为在BackgrounDRb进程的所有5个线程中共享的affected_rows使用了一些全局变量(类变量),但我不确定。我正在查看mysql gem和ActiveRecord的代码,但我无法理解它是如何工作的。

这怎么可能发生?

更新2010-07-07:我们决定不使用线程进行作业处理 - 这将解决我们所有的问题:每个作业处理器都是一个单独的过程:)

0 个答案:

没有答案