Cette page décrit comment configurer la réessai de tâches.

Comportement par défaut

Par défaut, asynq réessaiera une tâche un maximum de 25 fois. Chaque fois que la tâche est réessayée, elle utilise une stratégie de recul exponentiel pour calculer le délai de réessaie. Si une tâche épuise toutes ses tentatives de réessaie (par défaut 25 fois), la tâche sera déplacée à l'état archivé pour des fins de débogage et d'inspection, et ne sera pas réessayée automatiquement (vous pouvez toujours exécuter manuellement la tâche en utilisant l'interface en ligne de commande (CLI) ou l'interface utilisateur web (WebUI)).

Les propriétés de réessaie de tâches suivantes peuvent être personnalisées :

  • Tentatives de réessaie maximales pour chaque tâche
  • Intervalle de temps à attendre avant qu'une tâche en échec puisse être réessayée (c'est-à-dire le délai)
  • Utilisation ou non du compteur de réessaie de la tâche
  • Sauter ou non les réessaies et envoyer directement la tâche à l'archive

Les parties restantes de cette page décrivent chacune des options personnalisées mentionnées ci-dessus.

Personnalisation du nombre maximal de tentatives de réessaie pour les tâches

Vous pouvez spécifier le nombre maximal de tentatives de réessaie pour une tâche lors de l'enfilement de la tâche en utilisant l'option asynq.MaxRetry.

Exemple:

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

Cela indique que la tâche devrait être réessayée au plus cinq fois.

Alternativement, si vous souhaitez définir le nombre maximal de tentatives de réessaie pour une tâche particulière, vous pouvez le définir en tant qu'option par défaut pour la tâche.

task := asynq.NewTask("feed:import", nil, asynq.MaxRetry(5))
client.Enqueue(task) // MaxRetry défini à 5

Personnalisation du délai de réessaie

Vous pouvez spécifier comment calculer le délai de réessaie en utilisant l'option RetryDelayFunc dans la structure Config.

La signature de RetryDelayFunc est la suivante :

// n est le nombre de fois que la tâche a été réessayée
// e est l'erreur renvoyée par le gestionnaire de tâches
// t est la tâche associée
RetryDelayFunc func(n int, e error, t *asynq.Task) time.Duration

Exemple:

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

Cela indique que toutes les tâches en échec attendront deux secondes avant d'être traitées à nouveau.

Le comportement par défaut est un recul exponentiel, défini par DefaultRetryDelayFunc. L'exemple suivant montre comment personnaliser le délai de réessaie pour des types de tâches spécifiques :

srv := asynq.NewServer(redis, asynq.Config{
    // Pour les tâches "foo", utilisez toujours un délai de 2 secondes, les autres tâches utilisent le comportement par défaut.
    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) 
    },
})

Erreur de non-échec

Parfois, vous pouvez souhaiter renvoyer une erreur du gestionnaire et réessayer la tâche ultérieurement, mais sans utiliser le compteur de réessaie de la tâche. Par exemple, vous pouvez vouloir réessayer ultérieurement car l'unité de travail n'a pas suffisamment de ressources pour gérer la tâche. Lors de l'initialisation du serveur, vous pouvez choisir de fournir une Config pour la fonction IsFailure(error) bool. Cette fonction prédicative détermine si l'erreur renvoyée par le gestionnaire compte comme un échec. Si la fonction renvoie false (c'est-à-dire une erreur de non-échec), le serveur n'utilisera pas le compteur de réessaie de la tâche et planifiera simplement la tâche pour un réessaie ultérieur.

Exemple :

var ErrResourceNotAvailable = errors.New("aucune ressource n'est disponible")

func HandleResourceIntensiveTask(ctx context.Context, task *asynq.Task) error {
    if !IsResourceAvailable() {
        return ErrResourceNotAvailable
    }
    // ...logique pour gérer la tâche intensive en ressources
}

// ...

srv := asynq.NewServer(redisConnOpt, asynq.Config{
    // ... autres options de configuration
    IsFailure: func(err error) bool {
        return err != ErrResourceNotAvailable // erreur de non-échec si aucune ressource n'est disponible
    },
})

Sauter le réessaie

Si Handler.ProcessTask renvoie une erreur SkipRetry, la tâche sera archivée quel que soit le nombre de réessaies restant. L'erreur renvoyée peut être SkipRetry ou une erreur enveloppée avec une erreur SkipRetry.

func ExampleHandler(ctx context.Context, task *asynq.Task) error {
    // Logique de gestion de tâches ici...
    // Si le gestionnaire sait que la tâche ne doit pas être réessayée, renvoyer SkipRetry
    return fmt.Errorf(": %w", asynq.SkipRetry)
}