📚 Pré-requisitos Teóricos: Este projeto prático aplica os conceitos essenciais ensinados na Especialização em Backend com PHP e Laravel. Recomendamos sua leitura para aprofundamento em mensageria assíncrona, workers e idempotência.
O Processamento de Pagamentos & Filas no Redis com Laravel aborda o desenvolvimento de uma infraestrutura financeira resiliente, capaz de absorver picos massivos de transações sem bloqueio de I/O. Utilizando Laravel 11, Redis Queues, webhooks do Stripe com validação de assinatura e garantias rígidas de idempotência, o sistema assegura tolerância a falhas e processamento garantido de pagamentos.
🏛️ Arquitetura do Pipeline Financeiro Assíncrono
O diagrama abaixo apresenta o fluxo desacoplado desde a notificação do webhook do Stripe até o processamento no worker daemon:
📁 Estrutura de Pastas Padronizada
A base de código segue o padrão canônico com nomenclatura anti-colisão:
catalogo_projetos/backend_php_03_queues_redis_stripe/
├── api-laravel/ # Backend de processamento assíncrono em Laravel 11
│ ├── app/
│ │ ├── Http/
│ │ │ └── Controllers/
│ │ │ └── StripeWebhookController.php # Endpoint com resposta imediata
│ │ ├── Jobs/
│ │ │ └── ProcessarPagamentoJob.php # Job assíncrono despachado no Redis
│ │ └── Models/
│ │ └── Pedido.php
│ ├── config/
│ │ ├── queue.php # Configuração de drivers de fila (Redis)
│ │ └── horizon.php # Monitoramento de throughput e workers
│ └── composer.json # Dependências: predis/predis, stripe/stripe-php
├── assets/ # Galeria de diagramas visuais e arquitetura
│ └── arquitetura_laravel_queues_stripe.svg
└── index.md # Especificação executiva e Padrão Ouro
🧑💼 Engenharia de Software & Requisitos
1. Histórias de Usuário (US)
| ID |
Persona |
História de Usuário |
Prioridade |
| US-01 |
Gateway Stripe |
Desejo receber resposta HTTP 200 imediata ao emitir webhooks para não acionar tentativas de reenvio redundantes. |
Alta |
| US-02 |
Comprador Online |
Desejo que a confirmação do meu pedido seja processada com segurança sem travamento do checkout. |
Alta |
| US-03 |
Auditor Financeiro |
Desejo garantia absoluta de idempotência para evitar cobranças ou liberações duplicadas do mesmo pagamento. |
Alta |
| US-04 |
Engenheiro de Confiabilidade (SRE) |
Desejo políticas de retentativa automática com retardo progressivo em caso de instabilidades temporárias de rede. |
Média |
| US-05 |
Operador de Suporte |
Desejo inspecionar transações que falharam na Dead-Letter Queue e reprocessá-las com um comando. |
Média |
2. Requisitos Funcionais (RF)
| ID |
Nome |
Descrição |
| RF-01 |
Validação de Assinatura |
Validar o cabeçalho Stripe-Signature via SDK oficial antes de processar qualquer payload de webhook. |
| RF-02 |
Despacho Assíncrono |
Enfileirar o job ProcessarPagamentoJob na fila prioritária payments do Redis. |
| RF-03 |
Checagem de Idempotência |
Verificar se o event_id do Stripe já foi processado no banco relacional antes de executar a transação. |
| RF-04 |
Transação Atômica |
Executar a atualização do status do pedido e criação da fatura dentro de um bloco DB::transaction. |
| RF-05 |
Dead-Letter Queue |
Persistir jobs que excederam o número máximo de tentativas na tabela failed_jobs. |
3. Requisitos Não-Funcionais (RNF)
| ID |
Nome |
Descrição |
| RNF-01 |
Latência de Acknowledgment |
Endpoint de webhook deve responder com HTTP 200 em menos de 80ms. |
| RNF-02 |
Tolerância a Falhas |
Configurar $tries = 3 e $backoff = [15, 60, 300] para retentativas escalonadas. |
| RNF-03 |
Performance de Fila |
Driver Redis em memória com throughput suportado superior a 1.000 jobs por minuto por worker. |
| RNF-04 |
Logging Estruturado |
Logs com contexto da transação (ID do evento, valor, status) para auditoria contínua. |
| RNF-05 |
Compatibilidade de Daemon |
Suporte pleno a orquestração via Laravel Horizon ou Supervisor em contêineres Docker. |
4. Diagrama de Casos de Uso
flowchart TD
subgraph Atores
STR["Stripe Webhook Gateway"]
WRK["Worker Daemon (Redis)"]
SRE["Operador / SRE"]
end
subgraph "Processador de Pagamentos (api-laravel)"
UC1["Validar Assinatura HMAC do Stripe"]
UC2["Despachar Job para Fila Redis"]
UC3["Verificar Idempotência do Evento"]
UC4["Atualizar Pedido em Transação Atômica"]
UC5["Gerenciar Falhas na Dead-Letter Queue"]
end
STR --> UC1
UC1 --> UC2
WRK --> UC3
UC3 --> UC4
WRK --> UC5
SRE --> UC5
5. Matriz de Rastreabilidade (RTM)
| Requisito Funcional |
Histórias Atendidas |
Requisitos Não-Funcionais |
Status de Cobertura |
| RF-01 (Validação de Assinatura) |
US-01, US-03 |
RNF-01, RNF-04 |
Implementado ✅ |
| RF-02 (Despacho Assíncrono) |
US-01, US-02 |
RNF-01, RNF-03 |
Implementado ✅ |
| RF-03 (Checagem de Idempotência) |
US-03 |
RNF-02, RNF-04 |
Implementado ✅ |
| RF-04 (Transação Atômica) |
US-02, US-03 |
RNF-02, RNF-04 |
Implementado ✅ |
| RF-05 (Dead-Letter Queue) |
US-04, US-05 |
RNF-02, RNF-05 |
Implementado ✅ |
🛠️ Implementação do Job Assíncrono (api-laravel/app/Jobs/ProcessarPagamentoJob.php)
<?php
namespace App\Jobs;
use App\Models\Pedido;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class ProcessarPagamentoJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public int $tries = 3;
public array $backoff = [15, 60, 300];
public function __construct(
public string $eventId,
public string $pedidoId,
public float $valor,
public string $statusPagamento
) {
$this->onQueue('payments');
}
public function handle(): void
{
Log::info("Iniciando processamento assincrono do evento: {$this->eventId}");
// Garantia de idempotencia no nivel de banco
$eventoProcessado = DB::table('stripe_events')
->where('event_id', $this->eventId)
->exists();
if ($eventoProcessado) {
Log::warning("Evento duplicado detectado e descartado: {$this->eventId}");
return;
}
DB::transaction(function () {
// Atualizar status do pedido
Pedido::where('id', $this->pedidoId)->update([
'status' => 'pago',
'valor_confirmado' => $this->valor,
]);
// Registrar processamento para assegurar idempotencia
DB::table('stripe_events')->insert([
'event_id' => $this->eventId,
'pedido_id' => $this->pedidoId,
'created_at' => now(),
]);
});
Log::info("Pagamento do pedido {$this->pedidoId} confirmado com sucesso.");
}
}
🚀 Roteiro de Execução
1. Iniciar Redis e Aplicação Laravel
cd catalogo_projetos/backend_php_03_queues_redis_stripe/api-laravel
composer install
php artisan migrate
2. Iniciar o Worker de Filas do Redis
php artisan queue:work redis --queue=payments --tries=3
3. Simular Disparo de Webhook via Stripe CLI
stripe trigger checkout.session.completed
🎯 Matriz de Checkpoints de Entrega
| Checkpoint |
Critério de Aceite |
Validação |
Status |
| CP-01 |
Receptor de webhook respondendo HTTP 200 sob assinatura válida |
Validação HMAC concluída com sucesso |
PASS ✅ |
| CP-02 |
Job ProcessarPagamentoJob inserido na fila payments do Redis |
Registro de mensagem visualizado no Redis CLI |
PASS ✅ |
| CP-03 |
Idempotência impedindo duplo processamento do mesmo event_id |
Descarte de execução duplicada sem erro |
PASS ✅ |
| CP-04 |
Transação atômica do banco atualizando o status do pedido |
Persistência íntegra em DB::transaction |
PASS ✅ |
| CP-05 |
Retentativas automáticas e captura em failed_jobs em caso de erro |
Registro gravado na Dead-Letter Queue |
PASS ✅ |