Sidekiq Github wiki 中文文档
错误支持
commit信息:Should this be a symbolized key based on https://github.com/mperham/sidekiq/blob/455e9d56f46f0299eaf3b761596207e15f906a39/lib/sidekiq/job_retry.rb#L68 | 提交者:scotteknight | 提交时间:2019-07-20 | 版本:27026c2
我讨厌说这这些,但是在执行作业时你的一些workers可能会引发异常。这是确实存在的。
Sidekiq有许多功能来处理所有类型的错误。
最佳实践
- 使用错误支持服务 - Honeybadger, Airbrake, Rollbar, BugSnag, Sentry, Exceptiontrap, Raygun等等。它们有着相似的功能和定价 请选一个并且使用它。当每有一个作业异常时,错误支持服务将发送给你一个邮件(像Honeybadger这样智慧的会在第1次,第3次和第10次相同错误时发送邮件,因此在成千上万的作业失败时,你的邮箱将不会被淹没。)
- 让Sidekiq捕获你的作业引发的错误。Sidekiq的内建重试机制将捕获这些异常并且定期重试这些作业。错误支持服务将提醒你这个异常,你修复这个异常,然后Sidekiq将成功重试你的作业。
- 如果你不在25次重试之内(大概21天)修复这个bug,Sidekiq将停止重试并且把你的作业移动到死亡状态位置。你可以修复bug并且在接下来的6个月里使用Web UI手动重试这个作业。
- 在6个月之后,Sidekiq将丢弃这个作业。
错误处理服务
Gems 能够绑定到Sidekiq的全局错误处理,因此当任意时间Sidekiq发生错误时,它们将被通知到。通过向你的应用的Gemfile文件里添加它们的gem, 应该所有的这些错误支持服务将自动集成。
通过给call(exception, context_hash)
提供一些信息 , 你可以创建你自己的错误处理程序:
Sidekiq.configure_server do |config|
config.error_handlers << Proc.new {|ex,ctx_hash| MyErrorService.notify(ex, ctx_hash) }
end
注意:错误处理程序仅仅跟Sidekiq服务进程有关系。例如,它们在Rails console中不活动。
回朔跟踪日志记录
为一个作业开启 backtrace
日志记录,在作业存在期间,作业产生的回朔将被暂时保存。小心:每个回朔可能在Redis里占据 1-4k的内存,因此大量的失败作业可能极大的提高你的Redis的内存使用。
sidekiq_options backtrace: true
在启用“backtrace”时,你应该小心,将它限制在几行之内,或者使用错误处理服务来跟踪失败作业和记录有关的回朔。
sidekiq_options backtrace: 20 # top 20 lines
自动作业重试、
Sidekiq将使用这个公式(retry_count ** 4) + 15 + (rand(30) * (retry_count + 1))
(也就是 15, 16, 31, 96, 271, ... 秒 + 一个随机的时间)以指数级推后时间来重试失败的作业。覆盖大概21天时间,它将提供25次重试。假如你在这个时间之内部署了bug修复代码,这个作业将重试并且成功执行。在25次重试之后,Sidekiq将把这个作业移动到死亡作业队列,如果那样,为了能够执行这个作业需要你手动干预。
通过添加以下示例到你的sidekiq.yml
文件,可以全局配置最大重试次数:
:max_retries: 1
这个表格包含大概的重试等待时间(点击展开)
# | 下次重试推后 | 总计等待时间
1 | 0d 0h 0m 30s | 0d 0h 0m 30s
2 | 0d 0h 0m 46s | 0d 0h 1m 16s
3 | 0d 0h 1m 16s | 0d 0h 2m 32s
4 | 0d 0h 2m 36s | 0d 0h 5m 8s
5 | 0d 0h 5m 46s | 0d 0h 10m 54s
6 | 0d 0h 12m 10s | 0d 0h 23m 4s
7 | 0d 0h 23m 36s | 0d 0h 46m 40s
8 | 0d 0h 42m 16s | 0d 1h 28m 56s
9 | 0d 1h 10m 46s | 0d 2h 39m 42s
10 | 0d 1h 52m 6s | 0d 4h 31m 48s
11 | 0d 2h 49m 40s | 0d 7h 21m 28s
12 | 0d 4h 7m 16s | 0d 11h 28m 44s
13 | 0d 5h 49m 6s | 0d 17h 17m 50s
14 | 0d 7h 59m 46s | 1d 1h 17m 36s
15 | 0d 10h 44m 16s | 1d 12h 1m 52s
16 | 0d 14h 8m 0s | 2d 2h 9m 52s
17 | 0d 18h 16m 46s | 2d 20h 26m 38s
18 | 0d 23h 16m 46s | 3d 19h 43m 24s
19 | 1d 5h 14m 36s | 5d 0h 58m 0s
20 | 1d 12h 17m 16s | 6d 13h 15m 16s
21 | 1d 20h 32m 10s | 8d 9h 47m 26s
22 | 2d 6h 7m 6s | 10d 15h 54m 32s
23 | 2d 17h 10m 16s | 13d 9h 4m 48s
24 | 3d 5h 50m 16s | 16d 14h 55m 4s
25 | 3d 20h 16m 6s | 20d 11h 11m 10s
提示: 这个表格是假设rand(30)
总是得到15时来计算出来的。
Web UI
Sidekiq Web UI 有“Retries”和"Dead"选项卡,来列出失败的作业以便你可以运行它们,审阅它们或者删除它们。
Dead 位置
这个Dead位置是一个围栏,那些所有重试都失败的作业被放在其中。Sidekiq将不再重试这些作业,你必须在这个UI中手动重试它们。这个Dead位置被限制为默认10,000个作业或者6个月之内的作业,因此它不会无限增长。仅仅配置为0次或者更多次重试的作业才会进入Dead 位置。 如果你想让特殊类型的作业仅仅执行一次,不关心会发生什么,你可以使用retry: false
设置。
配置
如果25是太多了,你可以为了一个特别的worker单独设置重试数:
class LessRetryableWorker
include Sidekiq::Worker
sidekiq_options retry: 5 # 仅仅重试5次,然后进入Dead 作业队列
def perform(...)
end
end
为了特别的worker,你可以关闭重试支持。
class NonRetryableWorker
include Sidekiq::Worker
sidekiq_options retry: false # 如果作业失败,它将被丢弃
def perform(...)
end
end
跳过重试,直接把失败作业放到Dead位置:
class NonRetryableWorker
include Sidekiq::Worker
sidekiq_options retry: 0
def perform(...)
end
end
你可以不让一个作业最终进入Dead位置:
class NoDeathWorker
include Sidekiq::Worker
sidekiq_options retry: 5, dead: false # 重试5次,如果不成功就消失掉
def perform(...)
end
end
如果需要,使用sidekiq_retry_in
可以定制重试间隔。
class WorkerWithCustomRetry
include Sidekiq::Worker
sidekiq_options retry: 5
# 当前重试数和异常来做yielded。这个块的返回值必须是一个整数。
# 它被以秒为单位作为间隔使用。
# 当返回值为nil时,将使用默认间隔值。
sidekiq_retry_in do |count, exception|
case exception
when SpecialException
10 * (count + 1) # (i.e. 10, 20, 30, 40, 50)
end
end
def perform(...)
end
end
在多次重试后,如果你已经定义了sidekiq_retries_exhausted
钩子,Sidekiq将在你的Worker上调用它。这个钩子接受队列消息作为参数。在Sidekiq移动作业到Dead位置之前,将调用这个钩子。
class FailingWorker
include Sidekiq::Worker
sidekiq_retries_exhausted do |msg, ex|
Sidekiq.logger.warn "Failed #{msg['class']} with #{msg['args']}: #{msg['error_message']}"
end
def perform(*args)
raise "or I don't work"
end
end
死亡提醒
这个sidekiq_retries_exhausted
回调对一个Worker类来说是特别的。从v5.1开始,当作业死亡时,Sidekiq也可以触发一个全局回调:
# this goes in your initializer
Sidekiq.configure_server do |config|
config.death_handlers << ->(job, ex) do
puts "Uh oh, #{job['class']} #{job["jid"]} just died with error #{ex.message}."
end
end
为了明白发生了什么糟糕的事情,你可以使用这个回调给自己发email,发一个懒信息等等。
程序崩溃
如果Sidekiq程序发生segfaults或是Ruby VM崩溃,被执行中的所有作业将丢失。Sidekiq Pro提供reliable queueing功能来支撑不丢失这些作业。
没有更多的Bike Shedding
Sidekiq的重试机制遵从着最佳实践设置,但是许多人为了支持他们自己的边缘用例,他们建议提供各种设置值和选项来进行调整。这样愚蠢至极。为了代码执行良好,设计你的代码遵从现存的Sidekiq重试机制,或者给JobRetry类打补丁来添加你的逻辑代码。除非你有一个 极其 吸引人的用例来说明为什么成千上万的Sidekiq用户想要这个改变,否则我不再接受任何重试机制的功能改变。