gpt4 book ai didi

ruby-on-rails - ActiveRecord touch 是否对多个工作人员是并发安全的?

转载 作者:行者123 更新时间:2023-12-04 03:34:49 24 4
gpt4 key购买 nike

假设我有两个工作人员(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)

问题的非并发版本:

  • 19:00:01:W1 触及 read_at
  • 19:00:02:W1 查询汽车,得到not read_at.nil? 最旧的car
  • 19:00:03:W1 向用户发送电子邮件。
  • 19:00:04:W2 触及 read_at
  • 19:00:05:W2 查询汽车,得到not read_at.nil? 最旧的汽车
  • 19:00:06:W2 返回,未发送电子邮件。
  • 用户收到 1 封电子邮件。

问题的并发版本:

  • 19:00:01:W1 触及 read_at。 AR 使用 read_at=19:00:01 向 DB 发送写入。 W1 与 DB 的连接出现问题,写入尚未执行。
  • 19:00:02:W2 触及 read_at。 AR 使用 read_at=19:00:02 向 DB 发送写入。 W2 连接良好,执行 DB 写入。
  • 19:00:03:W2 查询汽车,得到not read_at.nil? 最旧的汽车
  • 19:00:04:W2 发邮件给用户,W1 写还没有执行。
  • 19:00:05:对数据库执行 W1 写入。
  • 19:00:06:W1 查询汽车,得到not read_at.nil? 的最旧的car。现在来自 W1 的汽车是最旧的,写入是在 W2 之后执行的,但是由于命令是 read_at=19:00:01,因此来自 W1 的汽车将比来自 W2 的汽车更旧, read_at=19:00:02.
  • 19:00:07:W1 向用户发送电子邮件。
  • 用户收到 2 封电子邮件。

这种情况(并发版本)有可能发生吗?如果是这样,为什么 AR 不会使用 DB 函数通过 touch 更改时间戳(例如,postgresql NOW())。

使用 NOW() 将使 W1 read_at 始终比 W2 read_at 更新。

最佳答案

Rails 不使用数据库原生函数的一个很好的原因(如果不是主要原因)是您的数据库对您的 Rails 应用程序使用的时区一无所知。

一旦可以configure a timezone无论何时调用 car.touch(:read_at),Rails 都需要告诉您的数据库究竟要保存什么内容。

另一件要记住的事情是你的 worker 应该是idempotent .换句话说,您应该让您的代码了解这些可能的竞争条件并保护自己免受它们的影响。您可能已经想到的一种解决方案是为您的数据库事务添加适当的锁。

关于ruby-on-rails - ActiveRecord touch 是否对多个工作人员是并发安全的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49639683/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com