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)
}