为什么我的 Sidekiq 作业因模型的after_commit代码而失败?

Why does my Sidekiq job fail from a model's after_commit code?

提问人:aaronkelton 提问时间:11/17/2023 最后编辑:user3402754aaronkelton 更新时间:11/18/2023 访问量:67

问:

当我运行这个 Sidekiq 作业时,它成功创建了 Foo 记录。但是由于 Foo 引发了错误,整个作业失败并最终进入死作业队列。如果我修复错误并重新运行作业,它将创建另一个 Foo 记录(或在重试😬时这样做),这是不可取的。after_commitafter_commit

我希望在成功创建 Foo 记录后成功完成。该逻辑不应导致作业失败。PerformAndCreateFooJobafter_commit

  • 为什么被认为是这份工作的一部分?after_commit
  • 有没有办法将代码与作业解耦?after_commit
  • 如果没有办法解耦,有没有更好的模式可以采用?
class PerformAndCreateFooJob
  include Sidekiq::Job
  sidekiq_options retry: 0

  def perform = Foo.create
end
class Foo < ApplicationRecord
  after_commit -> () { raise }
end

dead job queue showing Perform and create foo job failed

Ruby-on-Rails 红宝石 Sidekiq

评论

2赞 Marian Theisen 11/17/2023
after_commit是创建的一部分,因此,如果它引发错误,作业将失败。根据你想要什么,为什么它失败,以及为什么你想“允许”它失败,你应该在after_commit代码或作业中挽救该错误
2赞 Stefan 11/17/2023
“有没有更好的模式可以采用”——到底做什么?为什么首先会有内部?你想达到什么目的?raiseafter_commit
0赞 aaronkelton 11/17/2023
@Stefan有没有更好的方法来解耦逻辑,这样工作就不会在表面上失败,咳咳......完成了它的工作:)显式是让读者知道逻辑错误的一种简洁方式(但实现细节与本文无关)。您可以想象它启动另一个作业,但假设调用该作业失败。after_commitraiseafter_commit
1赞 Stefan 11/17/2023
@aaronkelton 在调用时引发异常。由于这个例外,Sidekiq 得出结论,它没有完成它的工作,因此重试。如果您不希望 Sidekiq 重试,您可以只从 .after_commitcreaterescueafter_commit
1赞 Stefan 11/17/2023
关于“脱钩”——我发现很难在这里提出建议。异常通常表示某种错误。 另一方面,在数据库事务成功后执行。从成功时调用的回调中引发异常对我来说似乎是矛盾的。after_commit

答:

1赞 smathy 11/18/2023 #1

为什么被认为是这份工作的一部分?after_commit

因为它是 的一部分(实际上是 的一部分),你正在调用它。createsave

有没有办法将代码与作业解耦?after_commit

通过使用 insert 跳过回调,如指南中所述

如果没有办法解耦,有没有更好的模式可以采用?

值得补充...最佳做法是确保作业是幂等的。可以重试作业的原因有很多,包括你自己的应用逻辑,以及其他系统条件。在正常情况下,这可能像使用第一个一样简单(假设您的作业队列逻辑不太可能为相同的记录/数据创建多个作业),或者可能需要在数据库和逻辑中有一个唯一的约束来挽救那里的故障。find_by