发布于 2025-12-10 4 阅读
0

正确编写 Sidekiq Worker 代码 1. 不要将逻辑代码放在 Worker 中。2. 不要让 Worker 过大。3. 将代码组织到目录中。4. 规划 Sidekiq 执行计划和优先级方案。5. 定期检查 Sidekiq 任务。结论

正确编写 Sidekiq Workers

1.不要将逻辑放入你的工作程序中。

2.不要让你的工人太大。

3. 将代码组织到目录中。

4. 规划您的 Sidekiq 执行计划和优先级方案。

5.定期检查你的Sidekiq任务。

结论

像 Rails 控制器一样,将逻辑转储到 Sidekiq Worker 中很容易上手。它们像经典的命令式风格一样,全部集中在一个地方。但随着时间的推移,它会变得混乱,你会发现自己不得不创建新的 Sidekiq Worker,而不是仅仅修复或使用旧的

因此,在 Sidekiq 中的后台任务变得更加混乱之前,这里有一些我在我们团队中学到的技巧。

1.不要将逻辑放入你的工作程序中。

你一开始写了 10 行代码,然后想,这段代码放在这里应该没问题。六个月后,你发现需要对这段代码进行额外的检查。于是你又加了 20 行。然后,你的队友发现了一个 bug,你又加了 10 行

然后,一个新手觉得你的逻辑很棒。她想复用它。但是,嘿,这个逻辑很适合工作单元用例。他不想冒着在第一次部署时出问题的风险,而是直接把你的代码复制粘贴到他的工作单元里。真恶心。现在你有两个相同的代码副本,但演化方式不同。

重点是,逻辑几乎总是在不断增长。要负责任。花点时间思考一下逻辑应该放在哪里——在交互器、服务对象还是模型中,以及它应该放在哪里。

2.不要让你的工人太大。

Sidekiq 专为小型任务而设计。小型、轻量级的任务。它不适合长时间运行的 Worker。

那么,你怎么知道你的工人“太大”了?

这里有一个循环。例如,我们有一个与订单关联的发票模型。每次发出订单时,我们都会提供一张发票,并预留所订购商品的库存。发票自发出之日起 5 天后过期。因此,它会引导我们到这个工作线程……

class InvoiceExpirerWorker
  include Sidekiq::Worker
  include Sidetiq::Schedulable

  def perform
    expired_invoices = Invoices.expirable

    expired_invoices.each do |invoice|
      invoice.expire!
    end
  end
Enter fullscreen mode Exit fullscreen mode

现在,这段代码片段对您来说可能看起来无害,但是当您查看发票模型时,有 100 行代码与发票过期有关:取消订单、退回商品库存、向客户发送电子邮件、更新记录等。

想象一下,今天10,000 张发票到期,每张发票需要20 秒才能完全过期,乘以 10,000 张发票。

问题是,这项工作对于单个工人来说太过繁重。

我们团队里大概有十几个worker没能执行完。为什么?就是因为它处理的任务量远远超出了单个Sidekiq worker的设计能力。worker内存耗尽,Linux直接终止了那个任务,结果我们留下了数百张本该过期却迟迟未过期的发票。太棒了!

那么,我们现在该做什么?

使用主 Worker生成多个较小的 Worker。主 Worker 的任务是构建待过期发票列表。它会逐一检查这些发票,并为每个发票调用一个单独的 Worker。如果列表中有 10,000 张发票,则需要创建 10,000 个轻量级 Worker。

这样,由于每个工人不需要花费太长时间,因此完成的机会就更大

这是一个更好的模式:

class BatchInvoiceExpirerWorker
  include Sidekiq::Worker
  include Sidetiq::Schedulable

  def perform
    expired_invoices = Invoices.expirable

    expired_invoices.each do |invoice|
      InvoiceExpirerWorker.perform_async(invoice.id)
    end
  end
end

class InvoiceExpirerWorker
  include Sidekiq::Worker

  def perform(invoice_id)
    invoice = Invoice.find(invoice_id)
    invoice.expire!
  end
end
Enter fullscreen mode Exit fullscreen mode

以前,一个大型 Worker 需要 20 万秒才能完成(每天大约 55 小时),现在我们有 1 万个小型 Worker 排队,每个 Worker 运行 20 秒。这样就更好了。

3. 将代码组织到目录中。

我们一开始只有10名工人。后来增加到20名、40名、50名。现在,我们有100名工人apps/workers

帮自己一个忙。请将你的代码组织到目录中。

4. 规划您的 Sidekiq 执行计划和优先级方案。

如果你认为凌晨 3 点是添加工人的安全时间……那么,再想想。也许其他三个开发人员也想到了这一点,并且会在凌晨 3 点添加他们自己的工人。

让我们回到之前的例子,#2 中提到的 10,000 个小型发票过期工人——我们将其称为工人 1。例如,您决定在凌晨 3 点添加工人 1。然后,另一个工人——我们称之为工人 2——与工人 1 大约在同一时间排队。哎呀。如果工人 2 是一个时间紧迫的工人,您可能需要等待一个多小时才能得到它。

为了避免这种情况,可以创建一个跟踪器。它可以像 Google 电子表格一样简单,或者更好的是,一个自动化系统,这样你就不必在每次开发人员添加/更改 Sidekiq 计划后进行清理。跟踪器会为你提供哪些工作人员的计划安排在何时的最新视图。这样,你就可以避免工作人员 1 妨碍对时间要求更高的工作人员 2。

现在,别就此止步。有些情况下,某个工人必须优先于其他工人,你也必须考虑到这一点。

假设您计划让 Worker 2 以更高的优先级运行。这样,当它在凌晨 3:05 左右运行时,它将先于 Worker 1 运行。

但是,如果将来有人在当前计划的作业之上添加了另一个优先级更高或相等的作业(例如,作业 3、作业 4 等),该怎么办?这会导致你的作业完成延迟。

Sidekiq 中的优先级排序是通过将工作线程组织到队列中来实现的。每个队列在 Sidekiq 中都有相应的优先级。更多信息请阅读:https: //github.com/mperham/sidekiq/wiki/Advanced-Options

因此,最好同时规划优先级和计划工作者的时间,以便有更好的机会加快 Sidekiq 执行时间,并降低 Sidekiq 实例的利用率不足。

5.定期检查你的Sidekiq任务。

之前的任务可能只需要几秒钟。现在订单量增加了 10 倍,这个任务可能需要 5 分钟。快进到今年,它甚至可能都执行不完。现在是时候根据上述原则重构这个 Worker 了。

结论

我希望这篇博文能帮你节省整理 Sidekiq Worker 的时间和精力。通过建立标准化的实践,你可以省去自己(以及所有人!)审查代码或查找 Worker 失败原因的麻烦。

特别感谢我的编辑 Allen,他帮助我使这篇文章更加连贯

鏂囩珷鏉ユ簮锛�https://dev.to/raphael_jambalos/coding-sidekiq-workers-the-right-way-4jij