一架梯子,一头程序猿,仰望星空!
Asynq任务队列教程 > 内容正文

任务重试


本页面介绍如何配置任务重试。

默认行为

默认情况下,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)
}