Ir para o conteúdo
DedicatedPHP Contato

Como projetar uma fila de tarefas para operações lentas em PHP

Saiba quando mover uma operação para fora da requisição web e como gerir estados, progresso, resultados, cancelamento e erros com segurança.

Diagrama conceitual do ciclo de vida de uma tarefa PHP: pendente, em processamento, concluída, com falha ou cancelada

Uma operação que demora vários segundos pode deixar uma requisição HTTP aberta, consumir recursos do servidor web e oferecer ao usuário uma experiência incerta se a conexão for interrompida. Os processos em segundo plano em PHP permitem aceitar o trabalho e executá-lo fora do ciclo de vida dessa requisição. Para que a solução seja útil, não basta adicionar uma fila: é preciso definir o que o usuário recebe, como consulta o estado e o que acontece em caso de interrupção.

Identificar quais operações devem ser executadas em segundo plano

Identificar quais operações devem ser executadas em segundo plano — guía visual de DedicatedPHP

Convém avaliar o impacto de uma operação, em vez de aplicar uma regra baseada apenas na duração. Uma tarefa pode ser candidata se o tempo de execução for variável, se exigir espera por um sistema externo ou se processar muitos elementos. Alguns exemplos são gerar um relatório extenso, importar um arquivo, transformar documentos ou sincronizar dados com uma API.

Por outro lado, se o usuário precisar de uma decisão imediata para continuar — como validar um dado essencial antes de salvar —, pode ser melhor manter essa parte na requisição e separar apenas o trabalho posterior. Há também tarefas lentas que exigem uma resposta síncrona por requisitos de negócio. A arquitetura deve atender às necessidades do fluxo, e não transformar cada operação em um trabalho assíncrono.

Antes de alterar o design, identifique quanto tempo a operação leva, que parte consome esse tempo e o que acontece se ela falhar. Uma fila não corrige, por si só, consultas ineficientes, limites mal configurados nem dependências externas instáveis; ela pode transferir esses problemas para os workers em segundo plano.

Responder com uma tarefa aceita, não com um resultado inventado

Quando o trabalho é aceito para execução posterior, a resposta da aplicação deve distinguir claramente entre aceito e concluído. Ela pode retornar um identificador de tarefa e indicar que o processamento está pendente. Não deve apresentar como concluído um resultado que ainda não existe.

Uma estimativa de duração só é apropriada se houver informações suficientes para calculá-la e comunicar sua incerteza. Em muitos sistemas, é mais honesto mostrar um estado como “na fila” ou “em processamento” do que prometer um horário de conclusão. Se a tarefa puder ser concluída rapidamente, a interface ainda poderá consultar o estado e mostrar o resultado quando estiver disponível, sem bloquear a requisição original.

Defina também o que acontece se o envio para a fila falhar: a aplicação não deve confirmar a aceitação se não conseguir registrar o trabalho de forma confiável. O mecanismo específico depende da arquitetura, mas a resposta e o estado persistido devem ser coerentes.

Definir estados e transições válidas

Um ciclo de vida pequeno e explícito facilita a experiência do usuário e a operação. Como base, podem ser considerados pendente, em_processamento, cancelamento_solicitado, concluída, com_falha e cancelada. Os nomes podem variar; as transições, por sua vez, devem ser válidas e verificáveis, e não uma combinação livre de estados.

  • Transições normais: pendente → em_processamento e, a partir de em_processamento, concluída ou com_falha.
  • Cancelamento antes do início: pendente → cancelada se for confirmado que o worker ainda não iniciou o trabalho.
  • Cancelamento durante a execução: em_processamento → cancelamento_solicitado. A partir desse estado, a tarefa passa para cancelada se for interrompida com segurança; pode passar para concluída se terminar antes de a solicitação ser atendida, ou para com_falha se ocorrer um erro.
  • Estados finais: concluída, com_falha e cancelada não devem voltar a estados ativos. Se for permitido repetir uma tarefa, crie uma nova execução ou defina explicitamente um ciclo diferente.

O sistema deve impedir transições não permitidas e registrar quando cada alteração ocorreu. Se um worker for interrompido e deixar uma tarefa em em_processamento, não a marque automaticamente como concluída. Uma política de recuperação pode devolvê-la a pendente quando for seguro retomá-la, ou marcá-la como com_falha para revisão. A decisão depende de ser possível retomar o trabalho sem duplicar efeitos. A coordenação de novas tentativas e a idempotência exigem decisões próprias; não devem ser confundidas com o modelo de estados visível.

Comunicar progresso, resultado e erros

O progresso deve se basear em marcos mensuráveis. Se não for possível calcular uma porcentagem real, é preferível informar a etapa (“validando dados”, “gerando relatório”) ou manter o estado “em processamento”. Uma porcentagem que não muda ou retrocede sem explicação reduz a confiança.

Ao concluir, apresente o resultado de negócio: por exemplo, um resumo dos elementos processados ou uma referência ao recurso gerado, conforme as permissões e a disponibilidade. O estado da tarefa não precisa armazenar o resultado inteiro. Pode guardar uma referência a dados geridos pelo domínio da aplicação.

Em caso de falha, apresente uma mensagem que ajude a decidir o próximo passo, como corrigir um arquivo ou tentar novamente quando for adequado. Registre separadamente o erro técnico necessário para o diagnóstico, com acesso restrito. Não exponha rastros de execução, credenciais, caminhos internos nem dados sensíveis na interface ou em uma API pública.

Tratar o cancelamento como uma solicitação com limites

Cancelar uma tarefa nem sempre significa que ela pode ser interrompida imediatamente. Um worker pode estar executando uma chamada externa, gravando dados ou em uma etapa que não admite interrupções seguras. Por isso, a interface deve distinguir entre cancelamento_solicitado e cancelada: o primeiro indica que a solicitação foi recebida; o segundo, que o sistema confirmou a interrupção.

A implementação pode verificar um sinal de cancelamento em pontos seguros e deixar de iniciar etapas posteriores. Se o efeito já tiver sido confirmado em um sistema externo, não se deve afirmar que foi desfeito. Explique ao usuário qual resultado pode esperar e registre quem solicitou o cancelamento quando essa informação for relevante para auditoria.

Separar o registro da tarefa do resultado de negócio

O registro de uma tarefa serve para coordenar a execução e a consulta: pode incluir um identificador, estado, datas, solicitante e referências para diagnóstico. O resultado de negócio — por exemplo, um relatório ou os registros importados — pertence ao modelo de dados que representa esse resultado.

Separá-los evita que uma tarefa com informações temporárias se torne a única fonte de dados do negócio. Também permite definir a retenção: por quanto tempo o estado será mantido, quando um arquivo será excluído e quais informações devem ser preservadas por obrigações operacionais ou normativas. Estados antigos não devem se acumular sem uma política de limpeza.

Proteger as consultas e limitar o consumo de recursos

Consultar uma tarefa exige autorização, assim como consultar qualquer outro recurso. O identificador não substitui o controle de acesso: verifique se a pessoa ou o sistema solicitante pode visualizar essa tarefa e seu resultado. Limite também a frequência e o volume das consultas para evitar polling excessivo e considere notificações quando o caso de uso não exigir atualizações constantes.

A execução deve ter limites de concorrência e recursos adequados ao tipo de trabalho. Muitos workers podem sobrecarregar o banco de dados, serviços externos ou armazenamento; poucos podem acumular tarefas e atrasar os resultados. Monitore o volume pendente, a idade das tarefas e as durações, além dos erros. Esses sinais ajudam a distinguir uma dependência lenta de um problema de capacidade.

Testar o ciclo completo antes de implantar

Os testes de aceitação devem cobrir o comportamento visível e a persistência, e não apenas verificar se o worker invoca uma função. Verifique pelo menos estes cenários:

  • A requisição cria uma tarefa e retorna uma referência sem afirmar que ela já terminou.
  • Uma tarefa concluída mostra o estado final e permite acessar o resultado com as permissões corretas.
  • Uma tarefa com falha comunica uma mensagem segura e deixa informações de diagnóstico acessíveis à equipe autorizada.
  • Uma tarefa abandonada ou interrompida não permanece indefinidamente “em processamento”; existe uma forma operacional de detectá-la e tratá-la.
  • Uma solicitação de cancelamento respeita as etapas seguras e não promete reverter efeitos já realizados.

Em um sistema existente, introduza a alteração em uma operação delimitada e valide também a experiência quando a fila estiver atrasada ou indisponível. A aplicação precisa de uma resposta clara para esses casos: informar que não conseguiu aceitar o trabalho, oferecer uma alternativa segura ou permitir que o usuário tente novamente. A decisão depende do impacto da operação e das garantias que o negócio pode sustentar.

Lista de verificação para introduzir uma fila em um sistema existente

Lista de verificação para introduzir uma fila em um sistema existente — guía visual de DedicatedPHP

Antes de habilitar o processamento em segundo plano, revise estes pontos com as equipes responsáveis pela aplicação e pela sua operação:

  • Escopo: foi escolhida uma operação específica e definido que parte continua síncrona e que trabalho será executado em segundo plano.
  • Persistência: a aceitação da tarefa e seu estado são salvos de forma coerente; existe uma política para interrupções, recuperação e alterações de estado.
  • Contrato com o usuário: a resposta inicial distingue aceitação de conclusão, e a interface explica como consultar o progresso, o resultado e os erros.
  • Permissões e dados: consultar uma tarefa ou seu resultado exige autorização; os dados armazenados são minimizados e o acesso às informações de diagnóstico é restrito.
  • Recursos: foram definidos limites de concorrência, tempo de execução, memória e frequência de consulta adequados à operação e às suas dependências.
  • Observabilidade: é possível detectar acúmulos, tarefas antigas em processamento, falhas e duração anormal sem incluir segredos nos logs.
  • Retenção: foi decidido por quanto tempo manter estados, resultados, arquivos e dados de diagnóstico, e como excluí-los de forma controlada.
  • Testes e operação: foram testados os caminhos de conclusão, falha, cancelamento e interrupção, e a equipe sabe o que fazer se a fila não aceitar trabalho ou estiver atrasada.

Implantar o código não equivale a habilitar imediatamente todos os fluxos: é possível introduzir gradualmente o novo caminho de execução e verificar seus sinais antes de ampliá-lo. Mantenha uma alternativa operacional adequada se a fila ou seus workers estiverem indisponíveis; não confirme trabalhos que o sistema não tenha conseguido registrar.

Deseja aplicar essas ideias ao seu projeto?Vamos discutir sua plataforma PHP.
Veja os serviços relacionados