Ta strona opisuje, jak skonfigurować ponowne próby zadania.

Domyślne zachowanie

Domyślnie, asynq spróbuje ponownie wykonać zadanie maksymalnie 25 razy. Za każdym razem, gdy zadanie jest ponawiane, obliczany jest opóźnienie za pomocą strategii wykładniczego powrotu. Jeśli zadanie wyczerpie wszystkie próby ponownego wykonania (domyślnie 25 razy), zadanie zostanie przeniesione do stanu zarchiwizowanego w celach debugowania i inspekcji, i nie będzie ponownie wykonywane automatycznie (nadal można ręcznie uruchomić zadanie za pomocą interfejsu wiersza poleceń (CLI) lub interfejsu użytkownika sieciowego (WebUI)).

Następujące właściwości ponownych prób zadania można dostosować:

  • Maksymalna liczba prób ponownego wykonania dla każdego zadania
  • Interwał czasowy oczekiwania przed ponowną próbą wykonania nieudanego zadania (tj. opóźnienie)
  • Czy używać liczby ponownych prób zadania
  • Czy pominąć ponowne próby i wysłać zadanie bezpośrednio do archiwum

Pozostałe części tej strony opisują każdą z powyższych opcji niestandardowych.

Dostosowywanie Maksymalnej Liczby Prób Ponownego Wykonania Zadań

Możesz określić maksymalną liczbę prób ponownego wykonania zadania podczas jego enqueuingu, korzystając z opcji asynq.MaxRetry.

Przykład:

client.Enqueue(task, asynq.MaxRetry(5))

Znaczy to, że task powinno być ponawiane maksymalnie pięć razy.

Alternatywnie, jeśli chcesz ustawić maksymalną liczbę prób ponownego wykonania dla konkretnego zadania, możesz ustawić ją jako domyślną opcję dla zadania.

task := asynq.NewTask("feed:import", nil, asynq.MaxRetry(5))
client.Enqueue(task) // MaxRetry ustawione na 5

Dostosowywanie Opóźnienia Ponownej Próby

Możesz określić sposób obliczania opóźnienia ponownej próby za pomocą opcji RetryDelayFunc w strukturze Config.

Sygnatura RetryDelayFunc jest następująca:

// n to liczba razy, kiedy zadanie zostało ponownie uruchomione
// e to błąd zwrócony przez obsługę zadania
// t to powiązane zadanie
RetryDelayFunc func(n int, e error, t *asynq.Task) time.Duration

Przykład:

srv := asynq.NewServer(redis, asynq.Config{
    Concurrency: 20,
    RetryDelayFunc: func(n int, e error, t *asynq.Task) time.Duration {
        return 2 * time.Second
    },
})

Znaczy to, że wszystkie nieudane zadania będą czekać dwa sekundy przed ponownym przetwarzaniem.

Domyślne zachowanie to wykładniczy powrót, zdefiniowany przez DefaultRetryDelayFunc. Poniższy przykład demonstruje, jak dostosować opóźnienie ponownej próby dla określonych typów zadań:

srv := asynq.NewServer(redis, asynq.Config{
    // Dla zadań "foo" zawsze użyj 2-sekundowego opóźnienia, inne zadania używają domyślnego zachowania.
    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) 
    },
})

Błąd niezwiązany z niepowodzeniem

Czasami możesz chcieć zwrócić błąd z obsługi i ponownie spróbować zadanie później, ale bez użycia liczby prób ponownego wykonania zadania. Na przykład, możesz chcieć spróbować ponownie później, ponieważ jednostka robocza nie ma wystarczających zasobów do obsługi zadania. Podczas inicjalizacji serwera, możesz wybrać dostarczenie Config dla funkcji predykatu IsFailure(error) bool. Ta funkcja predykatu określa, czy błąd z obsługi jest uznawany za niepowodzenie. Jeśli funkcja zwraca wartość fałsz (tj. błąd niezwiązany z niepowodzeniem), serwer nie będzie korzystać z liczby prób ponownego wykonania zadania i po prostu zaplanuje zadanie do późniejszej ponownej próby.

Przykład:

var ErrResourceNotAvailable = errors.New("no resource is available")

func HandleResourceIntensiveTask(ctx context.Context, task *asynq.Task) error {
    if !IsResourceAvailable() {
        return ErrResourceNotAvailable
    }
    // ... logika obsługi zadania wymagającego zasobów
}

// ...

srv := asynq.NewServer(redisConnOpt, asynq.Config{
    // ... inne opcje konfiguracyjne
    IsFailure: func(err error) bool {
        return err != ErrResourceNotAvailable // błąd niezwiązany z niepowodzeniem, jeśli nie ma dostępnych zasobów
    },
})

Pominięcie ponownego wykonywania

Jeśli Handler.ProcessTask zwraca błąd SkipRetry, zadanie zostanie zarchiwizowane niezależnie od pozostałej liczby ponownych prób. Zwracany błąd może być SkipRetry lub błąd opakowany w błąd SkipRetry.

func ExampleHandler(ctx context.Context, task *asynq.Task) error {
    // Logika obsługi zadania tutaj...
    // Jeśli obsługa wie, że zadanie nie powinno być ponownie wykonywane, zwróć SkipRetry
    return fmt.Errorf(": %w", asynq.SkipRetry)
}