Esta página descreve como configurar a repetição de tarefas.

Comportamento Padrão

Por padrão, asynq tentará repetir uma tarefa no máximo 25 vezes. Cada vez que a tarefa é repetida, utiliza uma estratégia de espera exponencial para calcular o atraso da repetição. Se uma tarefa esgota todas as tentativas de repetição (o padrão é 25 vezes), a tarefa será movida para o estado arquivado para fins de depuração e inspeção, e não será repetida automaticamente (ainda é possível executar manualmente a tarefa usando a CLI ou WebUI).

As seguintes propriedades de repetição de tarefas podem ser personalizadas:

  • Número máximo de tentativas de repetição para cada tarefa
  • Intervalo de tempo a aguardar antes que uma tarefa falha possa ser repetida (ou seja, atraso)
  • Se usar a contagem de repetições da tarefa
  • Se pular as repetições e enviar a tarefa diretamente para o arquivo

As partes restantes desta página descrevem cada opção personalizada mencionada acima.

Personalizando o Número Máximo de Tentativas de Repetição para Tarefas

É possível especificar o número máximo de tentativas de repetição para uma tarefa ao enfileirá-la usando a opção asynq.MaxRetry.

Exemplo:

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

Isto indica que a task deve ser repetida no máximo cinco vezes.

Alternativamente, se desejar definir o número máximo de tentativas de repetição para uma tarefa específica, é possível definir isso como uma opção padrão para a tarefa.

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

Personalizando o Atraso da Repetição

É possível especificar como calcular o atraso da repetição usando a opção RetryDelayFunc na estrutura Config.

A assinatura de RetryDelayFunc é a seguinte:

// n é o número de vezes que a tarefa foi repetida
// e é o erro retornado pelo manipulador da tarefa
// t é a tarefa relacionada
RetryDelayFunc func(n int, e error, t *asynq.Task) time.Duration

Exemplo:

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

Isto indica que todas as tarefas falhadas aguardarão dois segundos antes de serem processadas novamente.

O comportamento padrão é um atraso exponencial de retentativa, definido por DefaultRetryDelayFunc. O exemplo a seguir demonstra como personalizar o atraso da repetição para tipos específicos de tarefa:

srv := asynq.NewServer(redis, asynq.Config{
    // Para tarefas "foo", sempre utilizar um atraso de 2 segundos, as outras tarefas utilizam o comportamento padrão.
    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) 
    },
})

Erro de não falha

Às vezes, pode ser desejável retornar um erro do manipulador e repetir a tarefa posteriormente, mas sem utilizar a contagem de repetições da tarefa. Por exemplo, é possível que se queira repetir mais tarde porque a unidade de trabalho não possui recursos suficientes para lidar com a tarefa. Durante a inicialização do servidor, é possível escolher fornecer uma Config para a função IsFailure(error) bool. Esta função preditiva determina se o erro do manipulador conta como uma falha. Se a função retornar falso (ou seja, um erro de não falha), o servidor não usará a contagem de repetições da tarefa e simplesmente programará a tarefa para repetição posterior.

Exemplo:

var ErrResourceNotAvailable = errors.New("nenhum recurso disponível")

func HandleResourceIntensiveTask(ctx context.Context, task *asynq.Task) error {
    if !IsResourceAvailable() {
        return ErrResourceNotAvailable
    }
    // ... lógica para lidar com tarefa intensiva em recursos
}

// ...

srv := asynq.NewServer(redisConnOpt, asynq.Config{
    // ... outras opções de configuração
    IsFailure: func(err error) bool {
        return err != ErrResourceNotAvailable // erro de não falha se recurso não estiver disponível
    },
})

Pular repetição

Se Handler.ProcessTask retornar um erro SkipRetry, a tarefa será arquivada, independentemente da contagem de repetições restantes. O erro retornado pode ser SkipRetry ou um erro envolvido com o erro SkipRetry.

func ExampleHandler(ctx context.Context, task *asynq.Task) error {
    // Lógica de manipulação de tarefas aqui...
    // Se o manipulador souber que a tarefa não deve ser repetida, retornar SkipRetry
    return fmt.Errorf(": %w", asynq.SkipRetry)
}