Laravel Queues: Lidando com Erros com Elegância

Back-end Ferramentas Laravel Pacotes PHP Tutoriais
Laravel Queues: Lidando com Erros com Elegância

ProcessOrder

Introdução

Embora certamente não seja um conceito novo, as Filas se tornaram um recurso poderoso e prático dos frameworks modernos. Elas permitem que nossos aplicativos, normalmente bloqueados por threads, despachem tarefas de forma assíncrona, permitindo que os fluxos de trabalho e, principalmente, os usuários continuem. As expectativas são altas para que os sites sejam entregues rapidamente e tenham conteúdo na página para manter uma boa experiência do usuário. O Laravel é um framework PHP bem ajustado, e aproveitar o recurso de Fila é muito fácil. Não vou entrar na configuração das Filas do Laravel aqui, pois o que realmente quero explorar é o tratamento de erros nos Jobs executados na Fila.

Um dos desafios de usar filas, e isso não é específico do Laravel, é que os erros podem ser silenciosos ou desaparecer em backtraces. Uma chave de API incorreta ou uma interrupção temporária do serviço podem causar muitas dores de cabeça para os Jobs e, dependendo de como o tratamento de erros foi configurado, essas falhas podem gerar problemas sérios. Pode ser que um Job do SendMail continue acessando um serviço incorretamente, resultando em um erro. Com muitas tentativas, o serviço pode decidir bloquear o aplicativo ou, pior, gerar mais cobranças por exceder a largura de banda. A documentação do Laravel para Filas é muito boa e define muitas opções disponíveis para lidar com erros e problemas.

Lidando com Erros

Primeiro, vamos dar uma olhada rápida em como o Laravel lida com erros ao executar Jobs na Fila. Quando ocorre um erro em um Job, ele é automaticamente liberado de volta para a Fila e processado novamente. O número de vezes que o Job será processado depende do número máximo de tentativas definido pela aplicação ou na opção –tries do comando queue:work do Artisan. Além disso, um Job pode especificar seus próprios valores máximos de tentativas e tempo limite (entre outras configurações).

ProcessOrder


    

Se você quiser manipular as tentativas dinamicamente, em vez de adicionar a $tries propriedade, o seguinte método público pode substituí-la na classe Job:

tenta

Além de definir o valor $timeout, uma $failOnTimeout = true propriedade pode ser adicionada, o que significa que, se o tempo limite expirar, a tarefa falhará e não será repetida . Além disso, o seguinte método pode ser usado para repetir a tarefa, mas apenas por um período de tempo específico:

tentar novamente até  

Além desses métodos, um especialmente útil é backoff() . Isso permite definir uma estratégia como parte das tentativas:

Isso significa que a primeira tentativa levará 3 segundos, a segunda, 10 segundos e, finalmente, a terceira, 20 segundos. Ao trabalhar com uma API que pode ser conhecida por não lidar bem com o estresse, você pode usar isso para deixá-la "respirar" por um momento.

Nem todos os erros são iguais

Há uma variedade de erros que podem ocorrer ao processar um trabalho, mas eles se resumem a apenas alguns:

  1. Temporário — Interrupções, limitação de taxa, o temido deadlock do banco de dados.
  2. Permanente — Ativos ausentes, dados inválidos, etc., o que significa que tentar novamente não ajudará.

Erros temporários são bem tratados usando tentativas, enquanto um erro permanente pode saturar a fila. Como lidamos com isso? Se você encapsular seu código em um try/catch, poderá decidir nesse ponto com algo assim:

 

Nesse caso, uma exceção com taxa limitada liberará o Job de volta para a Fila, mas após um atraso de 60 segundos. Isso depende, é claro, dos limites da API. Se a conexão falhar devido a uma interrupção de rede ou credenciais incorretas, o erro pode ser tratado acionando a falha do Job. Em vez de passar a exceção para o fail() método, você também pode passar uma descrição em string.

O fail() método é especialmente útil antes que uma exceção seja disparada. Se, no seu código, o handle() método detectar que os dados não estão corretos ou que o processo, por qualquer motivo, não deve continuar, a chamada fail() pode interrompê-lo completamente. Certifique-se de passar a descrição do problema para o método fail também.

O middleware pode ser usado em um Job para definir quais exceções acionarão uma falha em vez de tentar novamente, adicionando o seguinte método à classe:

Reflexão tardia

Não deixe de visitar a documentação do Laravel sobre Filas e ler sobre tratamento de erros. Isso evitará muitas dores de cabeça no futuro. Como a comunidade Laravel é tão grande e ativa, você poderá encontrar diversas soluções para ajudar a lidar com erros, especialmente dependendo da infraestrutura selecionada para executar sua Fila (Redis, RabbitMQ, etc.). Dê uma olhada também no Horizon , que oferece um painel para monitorar sua Fila de Tarefas, além de alguns recursos excelentes, como suporte a balanceamento automático, métricas e notificações.