【问题标题】:How to assure the same job doesn't run twice at the same time?如何确保同一作业不会同时运行两次?
【发布时间】:2017-07-31 00:31:26
【问题描述】:

我有一个简单的 sidekiq 作业,我已将其设置为使用发条装置每 5 分钟运行一次。我担心的是,如果作业时间超过 5 分钟,它会再次运行,如果它与原始作业同时运行,可能会导致一些问题。

有没有办法锁定发条,使其仅在前一次运行完成时才运行?

【问题讨论】:

  • Sidekiq 企业版有独特的作业支持,如果你不想购买,可以在redis 中使用key 进行作业,并在作业运行时存储,作业完成后移除key。仅当 key 不存在时才将作业排入队列

标签: ruby-on-rails ruby sidekiq clockwork


【解决方案1】:

我已使用Sidekiq Unique Jobs gem 来完成此操作。它有多种防止重复作业的策略。

【讨论】:

  • 这个 Gem 需要 Sidekiq Enterprise 还是完全独立的 Gem?
  • 另外,我相信这个 Gem 不适用于 ActiveJob。
【解决方案2】:

Sidekiq Enterprise 包括对unique jobs 的支持。独特的工作是用工人类中的一个选项定义的:

# app/workers/my_worker.rb
class MyWorker
  include Sidekiq::Worker
  sidekiq_options unique_for: 10.minutes

  def perform(...)
  end
end

它们也必须在 Sidekiq 初始化程序中启用:

# config/initializers/sidekiq.rb
Sidekiq::Enterprise.unique! unless Rails.env.test?

时间窗口仅在作业运行时适用,例如,如果它在 10 分钟内是唯一的并且作业在 6 分钟内完成,那么 Sidekiq 将立即允许另一个作业入队;您无需再等待 4 分钟即可解除唯一性锁定。

在所有 Sidekiq Enterprise 节点上强制执行唯一性约束。

您可能需要调整您的retries 选项,因为失败的作业只要处于重试状态就会继续持有锁定。 (即使它没有主动执行)

【讨论】:

    【解决方案3】:

    Sidekiq 允许您通过 API 查询队列。

    您可以在任务运行时简单地查询 sidekiq 队列。检查队列和/或作业是否仍然存在。如果是,什么也不做。如果不是,请将作业排入队列。

    我不知道您的工作是否位于单独的队列中,这可能是最好的。这样你就可以查看队列大小,如果为 0 则启动另一个进程。

    Sidekiq API

    【讨论】:

      【解决方案4】:

      一种选择是在作业开始时使用进程 PID 创建一个文件,并在作业结束时将其删除,如果 PID 文件已经存在,则在开始时中止作业。

      虽然我的应用程序的这个特定部分没有使用 sidekiq,但想法是一样的。以下是我的应用程序的操作方式:https://github.com/WikiEducationFoundation/WikiEduDashboard/blob/master/lib/data_cycle/constant_update.rb

      【讨论】:

      • 这并不能保证作业是唯一的,因为 Sidekiq 可以跨多个节点同时运行,因此作业可能会或可能不会触发,具体取决于运行作业的节点。由于 Sidekiq 需要 Redis,因此更好的解决方案是使用 Redis 作为数据存储。一个例子是github.com/kenn/redis-mutex
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-02-28
      • 1970-01-01
      • 2018-09-28
      • 1970-01-01
      • 2011-01-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多