📚 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:

Arquitetura de Filas Redis e Stripe no Laravel

📁 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 ✅