我有一个包含以下环境的制作网站:
其中一个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:我们决定不使用线程进行作业处理 - 这将解决我们所有的问题:每个作业处理器都是一个单独的过程:)