Эта страница описывает, как настроить повторную попытку выполнения задачи.

Стандартное поведение

По умолчанию asynq будет повторять выполнение задачи максимум 25 раз. При каждой повторной попытке выполнения задачи используется стратегия экспоненциальной задержки перед повтором. Если задача исчерпает все свои попытки повтора выполнения (по умолчанию 25 раз), она будет перемещена в состояние archived для отладки и проверки, и не будет автоматически повторно выполняться (вы по-прежнему можете вручную запустить задачу с помощью 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

Настройка задержки повтора

Вы можете указать, как вычислять задержку повтора, используя опцию RetryDelayFunc в структуре Config.

Сигнатура 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)
}