假设我有两个工作人员(W1,W2)并行运行同一个作业(sidekiq不能保证一个作业只运行一次,所以可能会发生这种情况)。
作业:
car.touch(:read_at)
cars = Car.where.not(read_at: nil).order(read_at: :asc).limit(1)
send_user_email if cars.include?(car)问题的非并发版本:
read_at。not read_at.nil?获取最老的car。read_at。not read_at.nil?获取最老的car。问题的并发版本:
read_at。AR用read_at=19:00:01向数据库发送一个写。W1与DB的连接出现问题,并且尚未执行写操作。read_at。AR用read_at=19:00:02向数据库发送一个写。W2有很好的连接,执行DB写。not read_at.nil?获取最老的car。not read_at.nil?获取最老的car。现在,来自W1的car是最古老的,写是在W2之后执行的,但是由于命令是read_at=19:00:01,对于read_at=19:00:02,W1中的car将比W2中的car更老。这种情况(并发版本)有可能发生吗?如果是,那么AR为什么不使用DBs函数来用touch更改时间戳(例如,postgresql NOW())。
使用NOW()将使W1 read_at总是比W2 read_at更新。
发布于 2018-04-10 17:42:12
Rails不使用数据库本机函数的一个很好的原因(如果不是主要的原因)是,您的数据库不知道Rails应用程序使用的是哪个时区。
一旦您可以将配置时区转到您的数据库服务器之外的其他地方,每当您调用car.touch(:read_at)时,Rails都需要告诉您的数据库到底将保持什么。
另一件需要考虑的事情是,您的员工应该是幂等。换句话说,您应该让您的代码意识到这些可能的种族条件,并保护自己不受它们的影响。正如您可能已经想到的那样,一种解决方案是为数据库事务添加适当的锁。
https://stackoverflow.com/questions/49639683
复制相似问题