Imagine que sua empresa precisa gerar 10.000 faturas em PDF simultaneamente no fechamento do mês. Ou que seu sistema de relatórios precisa converter dashboards HTML em PDFs para envio automático aos clientes.
Converter HTML em PDF parece simples, até você precisar fazer isso em escala.
No mundo real, soluções mal arquitetadas causam:
- Timeouts e perdas de receita: servidores travados durante picos de demanda
- Experiência ruim para clientes: espera de minutos por um PDF que "nunca chega"
- Custos ocultos: infraestrutura superdimensionada para compensar ineficiência
- Retrabalho manual: equipes reprocessando jobs falhados manualmente
- Debugging caro: horas de engenharia investigando falhas intermitentes
Impacto real: em um cliente que implementei essa solução, reduzimos o tempo de geração de 30.000 PDFs/dia de 4 horas para 15 minutos, permitindo que equipes financeiras fechassem o mês mais cedo.
A Solução: Arquitetura Desacoplada e Resiliente
Visão Executiva (para não-técnicos)
Analogia: imagine uma pizzaria tradicional onde o atendente anota o pedido, faz a pizza, assa e entrega. Quando chegam 50 pedidos simultâneos, o sistema colapsa.
Nossa arquitetura funciona como um restaurante moderno:
- Recepção (API): aceita pedidos rapidamente e dá um número de protocolo
- Fila inteligente (NATS): organiza pedidos por prioridade e garante que nada se perca
- Cozinha paralela (Workers): múltiplas estações processando simultaneamente
- Controle de qualidade (Circuit Breaker): se o forno estraga, para de enviar pedidos até consertar
Resultado: atende 10x mais pedidos com a mesma equipe, sem perder qualidade.
Componentes: Decisões Técnicas com Impacto no Negócio
1. API RESTful Assíncrona (Go + Gin)
Decisão técnica: API retorna imediatamente com job_id, sem esperar o PDF ficar pronto.
Impacto no negócio:
2. NATS JetStream: A Escolha Estratégica
Por que NATS e não RabbitMQ/Kafka?
| Critério | NATS JetStream | RabbitMQ | Kafka |
|---|---|---|---|
| RAM consumida | 14MB | 500MB+ | 2GB+ |
| Custo AWS (t3.small) | $15/mês | $30/mês | $60/mês |
| Tempo de setup | 5min | 30min | 2h+ |
| Garantia de entrega | Nativa | Config | Complexa |
| DLQ automática | Built-in | Plugin | Manual |
ROI para o negócio: economia de $540/ano em infraestrutura + 80% menos tempo de DevOps.
3. Browser Pool: A Otimização de $15.000
Problema anterior: criar um browser Chromium do zero a cada PDF.
- Tempo: 2-4 segundos por PDF
- Custo: 6 servidores EC2 m5.large ($450/mês cada)
Solução: pool de 3 browsers reutilizáveis por worker.
- Tempo: <1 segundo por PDF (4x mais rápido)
- Custo: 2 servidores t3.medium ($70/mês cada)
Economia anual: $15.120 (87% de redução)
4. Circuit Breaker: Evitando o Efeito Dominó
Cenário real: S3 fica lento (latência passa de 200ms para 5s).
Sem Circuit Breaker:
- Workers ficam travados esperando S3
- Fila cresce indefinidamente
- Sistema todo fica lento (efeito cascata)
- Impacto: SLA de 30s vira 5 minutos → clientes abrem tickets
Com Circuit Breaker:
Estados:
1. Closed (normal): requisições fluem normalmente
2. Open (proteção): após 5 falhas, para de tentar por 30s
3. Half-Open (teste): tenta 1 request para validar recuperação
Resultado prático: durante uma instabilidade de 10min do S3, sistema continuou aceitando jobs (que foram processados assim que S3 voltou), sem timeouts para clientes.
5. Debug Mode: Economizando Horas de Engenharia
Problema clássico: "Funciona no meu computador, mas falha em produção!"
Causa: ambientes headless (sem interface gráfica) escondem erros de CSS, fontes, imagens.
Solução: Fila separada para debug
ROI: equipe reduziu tempo de troubleshooting de 4h para 20min em casos complexos.
6. Dead Letter Queue (DLQ): Zero Perda de Jobs
Problema: jobs que falham 3x eram perdidos (HTML malformado, timeouts, etc).
Solução: DLQ automática
Job falha 3x → NATS move automaticamente para "pdf_jobs_dlq"
Impacto: em 3 meses de produção, zero jobs perdidos (vs ~200/mês no sistema anterior).
Resultados em Produção
Performance
| Métrica | Antes | Depois | Melhoria |
|---|---|---|---|
| Throughput | 25 PDFs/min | 200 PDFs/min | 8x |
| Latência P95 | 35s | 8s | 4.4x |
| Taxa de sucesso | 94.2% | 99.7% | +5.5pp |
| Custo/1000 PDFs | $2.40 | $0.30 | -87% |
Recursos (por worker)
- RAM: ~800MB (vs 2.5GB anteriormente)
- CPU: 0.25 core idle, burst 1.0 core
- Disco: 500MB buffer NATS (24h de jobs)
Escalabilidade Real
Teste de carga Black Friday:
- Pico: 847 PDFs/minuto (28.000/dia habituais → 50.000 no pico)
- Ação: aumentamos de 2 para 5 workers via docker-compose scale
- Tempo de escala: 90 segundos
- Custo adicional: $0 (usamos instâncias spot AWS)
ROI Consolidado (Caso Real)
Empresa: SaaS B2B de gestão financeira
Volume: 30.000 PDFs/dia
Antes da Implementação
- Infraestrutura: 6x m5.large ($2.700/mês)
- Tempo de processamento: 4h/dia (bloqueava outras operações)
- Incidentes/mês: 12 (jobs perdidos, timeouts)
- Horas DevOps/mês: 40h debugging
- Custo total mensal: $7.200
Depois da Implementação
- Infraestrutura: 2x t3.medium ($140/mês)
- Tempo de processamento: 15min/dia
- Incidentes/mês: 0.3 (99% menos)
- Horas DevOps/mês: 4h (manutenção)
- Custo total mensal: $860
Economia anual: $76.080 (89% de redução)
Ganho operacional: 3h45min/dia (equipe financeira fecha mês mais cedo)
Lições Aprendidas
O que funcionou excepcionalmente
Desacoplamento via messaging: API nunca trava, mesmo com 1000 jobs na fila
Browser pooling: decisão técnica que gerou maior ROI ($15k/ano)
Circuit breakers: evitaram 100% dos incidentes de cascata
DLQ automática: zero perda de jobs em 6 meses de produção
Debug mode: ROI indireto gigante (horas de engenharia economizadas)
Armadilhas Evitadas
| Antipattern | Solução | Impacto evitado |
|---|---|---|
| API síncrona | Queue assíncrona | Timeouts em picos |
| Browser por request | Browser pooling | Custo 6x maior |
| Retry infinito | DLQ após 3 falhas | Loops infinitos |
| Headless only | Fila debug separada | 20h/mês debugging |
| Sem monitoring | Métricas NATS | SLA imprevisível |
Stack Técnica Completa
Backend: Go 1.21+ (Gin framework)
Queue: NATS JetStream 2.10
Automation: Playwright-Go (Chromium)
Storage: AWS S3 SDK v2
Deploy: Docker Compose + GitHub Actions
Monitoring: Prometheus + Grafana (métricas NATS)
Docs: Swagger/OpenAPI
Quando Você Precisa Dessa Arquitetura?
Use se você tem:
- Mais de 1.000 PDFs/dia
- Picos imprevisíveis (fechamento de mês, campanhas)
- SLA < 30s para entrega de PDFs
- Necessidade de auditoria (DLQ, logs)
- Time pequeno (solução auto-gerenciável)
Overkill se você tem:
- Menos de 100 PDFs/dia
- Carga totalmente previsível
- Deadline flexível (horas/dias)
Dúvidas Frequentes
P: Funciona com outras linguagens?
R: Sim! A arquitetura é language-agnostic. Já vi implementações em Python (FastAPI) e Node.js.
P: Quanto custa escalar para 1 milhão de PDFs/mês?
R: ~$300/mês em AWS (t3.medium + S3 + NATS).
P: Suporta PDFs com gráficos complexos (Chart.js, D3)?
R: Sim, Playwright renderiza JavaScript completo antes de gerar o PDF.
P: Como migrar de uma solução existente?
R: Implemente em paralelo (dual-write), valide com % do tráfego, depois migre 100%.
Conclusão
Se você está sofrendo com:
- Processamento assíncrono em escala
- Geração de PDFs/screenshots em produção
- Implementação de resilience patterns (circuit breaker, retry, DLQ)
Essa arquitetura já está validada em produção gerando milhões de PDFs/mês com 99.7% de sucesso.
Adapte, implemente e compartilhe seus resultados!
"Otimize o sistema, não apenas o código."
