本页面介绍如何配置任务重试。
默认行为
默认情况下,asynq
将重试任务最多 25 次。每次重试任务时,它使用指数退避策略来计算重试延迟。如果一个任务耗尽了所有的重试次数(默认为 25 次),该任务将移动到归档中用于调试和检查目的,并且不会自动重试(您仍然可以使用 CLI 或 WebUI 手动运行任务)。
以下任务重试的属性可进行自定义:
- 每个任务的最大重试次数
- 在失败的任务可以再次重试之前等待的时间间隔(即延迟)
- 是否使用任务的重试次数
- 是否跳过重试并直接将任务发送到归档
本页面的其余部分描述了上述每个自定义选项。
自定义任务的最大重试次数
您可以在入队任务时使用 asynq.MaxRetry
选项来指定任务可以重试的最大次数。
示例:
client.Enqueue(task, asynq.MaxRetry(5))
这表示 task
应该最多重试五次。
或者,如果您想为某个任务指定最大重试次数,可以将其设置为该任务的默认选项。
task := asynq.NewTask("feed:import", nil, asynq.MaxRetry(5))
client.Enqueue(task) // MaxRetry 设置为 5
自定义重试延迟
您可以在 Config
中使用 RetryDelayFunc
选项来指定如何计算重试延迟。
RetryDelayFunc
的签名如下:
// n 是任务已重试的次数
// e 是任务处理程序返回的错误
// t 是相关的任务
RetryDelayFunc func(n int, e error, t *asynq.Task) time.Duration
示例:
srv := asynq.NewServer(redis, asynq.Config{
Concurrency: 20,
RetryDelayFunc: func(n int, e error, t *asynq.Task) time.Duration {
return 2 * time.Second
},
})
这表示所有失败的任务将在再次处理之前等待两秒钟。
默认行为是指数退避,并由 DefaultRetryDelayFunc
定义。下面的示例展示了如何为特定任务类型自定义重试延迟:
srv := asynq.NewServer(redis, asynq.Config{
// 对于 "foo" 任务,始终使用 2 秒的延迟,其他任务使用默认行为。
RetryDelayFunc: func(n int, e error, t *asynq.Task) time.Duration {
if t.Type() == "foo" {
return 2 * time.Second
}
return asynq.DefaultRetryDelayFunc(n, e, t)
},
})
非失败错误
有时,您可能希望从处理程序返回一个错误并稍后重试任务,但不想使用任务的重试次数。例如,您可能希望稍后重试,因为工作单元没有足够的资源来处理任务。
在初始化服务器时,您可以选择为 Config
提供 IsFailure(error) bool
函数。该谓词函数确定来自处理程序的错误是否计为失败。如果该函数返回 false(即非失败错误),服务器将不会使用任务的重试次数,并简单地安排任务稍后进行重试。
示例:
var ErrResourceNotAvailable = errors.New("no resource is available")
func HandleResourceIntensiveTask(ctx context.Context, task *asynq.Task) error {
if !IsResourceAvailable() {
return ErrResourceNotAvailable
}
// ... 处理资源密集任务的逻辑
}
// ...
srv := asynq.NewServer(redisConnOpt, asynq.Config{
// ... 其他配置选项
IsFailure: func(err error) bool {
return err != ErrResourceNotAvailable // 如果没有可用资源,则为非失败错误
},
})
跳过重试
如果 Handler.ProcessTask
返回一个 SkipRetry
错误,不管剩余的重试次数是多少,任务都将被归档。返回的错误可以是 SkipRetry
或包装了 SkipRetry
错误的错误。
func ExampleHandler(ctx context.Context, task *asynq.Task) error {
// 任务处理逻辑在此处...
// 如果处理程序知道任务不需要重试,则返回 SkipRetry
return fmt.Errorf(": %w", asynq.SkipRetry)
}