Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

Design for Failure: Padrões de Resiliência

Design for Failure: Padrões de Resiliência

Essa talk, intitulada "Design for Failure – Padrões de Resiliência", apresenta de forma didática e descontraída os principais conceitos e práticas para criar sistemas resilientes, ou seja, capazes de continuar funcionando mesmo diante de falhas. A apresentação conduz o público desde cenários simples de infraestrutura até situações reais de indisponibilidade de serviços, demonstrando na prática padrões como Retry, Circuit Breaker, Fallback, Cache, Rate Limiting e o Saga Pattern. Exemplos em PHP (Hyperf) e TypeScript (NestJS) ilustram como implementar essas estratégias em diferentes linguagens. A talk enfatiza a importância de planejar para falhas inevitáveis, promovendo soluções que priorizam automação, alta disponibilidade e foco no negócio, utilizando recursos modernos como Cloud Computing, Docker e Kubernetes.

Acesse em: https://sschonss.github.io/design-for-failure/

Avatar for schons

schons

June 05, 2025
Tweet

More Decks by schons

Other Decks in Technology

Transcript

  1. QUEM SOU EU? Luiz Schons Senior Software Architect/Engineer @ Vivaworks

    Canionista / Montanhista Atleta de CA BJJ DevParaná UTFPR schons.hashnode.dev Polyglot.ai & Golazzo Uma curiosidade…
  2. DISCLAIMER Não sou especialista em nada Analise o cenário que

    você está Não existe bala de prata Estude e estude…
  3. MAS PERAI, SISTEMAS FALHAM? Sim, e por diversos motivos -

    software, hardware, rede ou fatores externos.
  4. O INÍCIO MODESTO Um computador antigo como servidor Instalação de

    servidor web e banco de dados Início do desenvolvimento do site Quem nunca começou assim? 😅
  5. SEU SUPER SERVIDOR 4GB de RAM Processador dual-core HD de

    500GB Sistema operacional + Servidor web + Banco de dados Parece até datacenter, não é mesmo? 🤣
  6. O SUCESSO TRAZ NOVOS DESAFIOS Com o aumento de usuários,

    seu servidor local começa a mostrar sinais de sobrecarga.
  7. MEU DEUS, O QUE FAZER? É hora de repensar a

    infraestrutura: escalar para suportar mais usuários e garantir a continuidade do serviço quando falhas ocorrerem.
  8. A SOLUÇÃO FUNCIONA... POR ENQUANTO Mas você esqueceu de um

    "pequeno" detalhe: servidores precisam de manutenção constante. E você não tem uma equipe de infraestrutura...
  9. SUPER-HERÓI DA INFRA Instalação de atualizações de segurança Monitoramento de

    recursos Resolução de problemas técnicos Manutenção do banco de dados Ah, e no tempo livre... desenvolver o seu e-commerce! 😰
  10. OS PESADELOS TE ASSOMBRAM E se o servidor parar de

    funcionar? E se ocorrer uma queda de energia? E se o disco rígido falhar? Meu negócio pode suportar esse risco?
  11. HORA DE ESCALAR COM ALTA DISPONIBILIDADE O próximo passo: múltiplos

    servidores para eliminar pontos únicos de falha e garantir que seu e-commerce esteja sempre disponível.
  12. ARQUITETURA DE ALTA DISPONIBILIDADE Infraestrutura robusta com servidor principal, backup

    e banco de dados separado — tudo configurado para continuar funcionando mesmo quando um componente falha.
  13. SEU DATACENTER CASEIRO TEM UM PROBLEMA Falta de monitoramento 24/7

    Vulnerabilidade a desastres físicos (incêndio, inundação) Riscos de segurança (roubo, invasão) Sua sala não foi projetada para ser um datacenter profissional...
  14. O CUSTO OCULTO DA "ECONOMIA" Investimento crescente em hardware Horas

    intermináveis de manutenção Tempo precioso desviado do seu negócio principal Estresse constante com a infraestrutura O barato sai caro... muito caro!
  15. PRECISAMOS DE ALGO MELHOR Uma solução que: Escale automaticamente conforme

    a demanda Ofereça alta disponibilidade sem dores de cabeça Permita foco no desenvolvimento do seu negócio
  16. E QUAL SERIA A SOLUÇÃO? Alguém tem alguma ideia? Quais

    opções temos hoje para: Escalar facilmente Reduzir manutenção Aumentar disponibilidade Focar no negócio
  17. A RESPOSTA: CLOUD COMPUTING Migração da infraestrutura para provedores especializados

    em nuvem que oferecem: Infraestrutura como serviço Escalabilidade sob demanda Alta disponibilidade com garantias por contrato Redução de responsabilidades operacionais
  18. NÃO ESTAMOS AQUI PARA FALAR DE INFRAESTRUTURA Mas sim de

    como projetar sistemas que sobrevivam quando as coisas dão errado Porque, acredite, elas sempre dão! 😅
  19. PROBLEMAS QUE PODEM OCORRER Serviço de pagamento fora do ar

    Serviço de calcular frete fora do ar Ataque em algum endpoint do sistema Complexidade ao adicionar mais um serviço
  20. CONCEITOS UNIVERSAIS, DIFERENTES LINGUAGENS Os padrões de resiliência funcionam em

    qualquer linguagem de programação Vamos ver exemplos em duas plataformas diferentes:
  21. EXEMPLO COM PHP E HYPERF use Hyperf\Retry\Annotation\Retry; use Hyperf\Retry\RetryBudget; namespace

    App\Service; 1 2 3 4 5 class PaymentService 6 { 7 #[Retry(delay: 1000, maxAttempts: 3)] 8 public function processPayment() 9 { 10 // make a remote call 11 class PaymentService namespace App\Service; 1 2 use Hyperf\Retry\Annotation\Retry; 3 use Hyperf\Retry\RetryBudget; 4 5 6 { 7 #[Retry(delay: 1000, maxAttempts: 3)] 8 public function processPayment() 9 { 10 // make a remote call 11 { #[Retry(delay: 1000, maxAttempts: 3)] public function processPayment() { // make a remote call namespace App\Service; 1 2 use Hyperf\Retry\Annotation\Retry; 3 use Hyperf\Retry\RetryBudget; 4 5 class PaymentService 6 7 8 9 10 11
  22. EXEMPLO COM TYPESCRIPT E NESTJS import { Retry } from

    '@nestjs/axios'; import { catchError, delay, retryWhen } from 'rx import { of } from 'rxjs'; import { Injectable } from '@nestjs/common'; 1 2 3 4 5 @Injectable() 6 export class PaymentService { 7 @Retry({ delay: 1000, maxAttempts: 3 }) 8 async processPayment() { 9 // make a remote call 10 } 11 export class PaymentService { @Retry({ delay: 1000, maxAttempts: 3 }) async processPayment() { // make a remote call } import { Injectable } from '@nestjs/common'; 1 import { Retry } from '@nestjs/axios'; 2 import { catchError, delay, retryWhen } from 'rx 3 import { of } from 'rxjs'; 4 5 @Injectable() 6 7 8 9 10 11
  23. MAS O RETRY TEM UM PROBLEMA... E se o serviço

    estiver completamente fora do ar? Vamos ficar tentando sem parar?
  24. COMO FUNCIONA? Inspirado nos disjuntores elétricos: Fechado (normal): Permite as

    chamadas ao serviço Aberto (falha): Bloqueia chamadas após muitos erros Semi-aberto: Permite algumas chamadas para testar recuperação
  25. RETRY VS CIRCUIT BREAKER RETRY Tenta novamente após falha Bom

    para falhas temporárias Pode sobrecarregar sistemas CIRCUIT BREAKER Evita chamadas a serviços falhos Bom para falhas persistentes Permite recuperação gradual Funcionam melhor quando usados em conjunto!
  26. IMPLEMENTAÇÃO EM PHP COM HYPERF class GatewayService p pp 2

    use App\Gateway\GatewayServiceClient; 3 use Hyperf\CircuitBreaker\Annotation\CircuitBrea 4 use Hyperf\Di\Annotation\Inject; 5 6 7 { 8 #[Inject] 9 private GatewayServiceClient $client; 10 11 #[CircuitBreaker 12 ( namespace App\Services; 1 2 use App\Gateway\GatewayServiceClient; 3 use Hyperf\CircuitBreaker\Annotation\CircuitBrea 4 use Hyperf\Di\Annotation\Inject; 5 6 class GatewayService 7 { 8 #[Inject] 9 private GatewayServiceClient $client; 10 11 namespace App\Services; 1 2 use App\Gateway\GatewayServiceClient; 3 use Hyperf\CircuitBreaker\Annotation\CircuitBrea 4 use Hyperf\Di\Annotation\Inject; 5 6 class GatewayService 7 { 8 #[Inject] 9 private GatewayServiceClient $client; 10 11 namespace App\Services; 1 2 use App\Gateway\GatewayServiceClient; 3 use Hyperf\CircuitBreaker\Annotation\CircuitBrea 4 use Hyperf\Di\Annotation\Inject; 5 6 class GatewayService 7 { 8 #[Inject] 9 private GatewayServiceClient $client; 10 11
  27. IMPLEMENTAÇÃO EM TYPESCRIPT COM NESTJS import { CircuitBreaker } from

    '@nestjs/axios'; import { Injectable } from '@nestjs/common'; 1 2 3 @Injectable() 4 export class PaymentService { 5 @CircuitBreaker({ 6 timeout: 5000, 7 fallback: () => 'Service unavailable' 8 }) 9 async processPayment() { 10 // make a remote call 11 export class PaymentService { @CircuitBreaker({ timeout: 5000, fallback: () => 'Service unavailable' }) import { Injectable } from '@nestjs/common'; 1 import { CircuitBreaker } from '@nestjs/axios'; 2 3 @Injectable() 4 5 6 7 8 9 async processPayment() { 10 // make a remote call 11 async processPayment() { // make a remote call import { Injectable } from '@nestjs/common'; 1 import { CircuitBreaker } from '@nestjs/axios'; 2 3 @Injectable() 4 export class PaymentService { 5 @CircuitBreaker({ 6 timeout: 5000, 7 fallback: () => 'Service unavailable' 8 }) 9 10 11
  28. O QUE SÃO FALLBACKS? Planos B para quando algo falha

    Podem ser simples mensagens ou lógicas alternativas complexas É como levar um guarda-chuva mesmo quando o céu está limpo 🌂
  29. FALLBACK EM PHP fallback: 'processPaymentFallback' // N #[CircuitBreaker 12 (

    13 options: ['timeout' => 5000], 14 failCounter: 3, 15 successCounter: 1, 16 17 )] 18 public function processPayment() 19 { 20 // make a remote call 21 } 22 namespace App\Services; 1 2 use App\Gateway\GatewayServiceClient; 3 use Hyperf\CircuitBreaker\Annotation\CircuitBrea 4 use Hyperf\Di\Annotation\Inject; 5 6 class GatewayService 7 { 8 #[Inject] 9 private GatewayServiceClient $client; 10 11
  30. FALLBACK EM TYPESCRIPT fallback: () => 'Service unavailable' / p

    j 3 @Injectable() 4 export class PaymentService { 5 @CircuitBreaker({ 6 timeout: 5000, 7 8 }) 9 async processPayment() { 10 // make a remote call 11 } 12 } 13
  31. COMPENSAÇÃO EM PHP COM HYPERF use Hyperf\Event\Contract\ListenerInterface; use App\Event\OrderCancelled; <!--?php

    1 namespace App\Listener; 2 3 4 5 6 class OrderCancelledListener implements Listener 7 { 8 public function listen(): array 9 { 10 return [OrderCancelled::class]; 11 public function listen(): array { return [OrderCancelled::class]; <!--?php 1 namespace App\Listener; 2 3 use Hyperf\Event\Contract\ListenerInterface; 4 use App\Event\OrderCancelled; 5 6 class OrderCancelledListener implements Listener 7 { 8 9 10 11 <!--?php 1 namespace App\Listener; 2 3 use Hyperf\Event\Contract\ListenerInterface; 4 use App\Event\OrderCancelled; 5 6 class OrderCancelledListener implements Listener 7 { 8 public function listen(): array 9 { 10 return [OrderCancelled::class]; 11 <!--?php 1 namespace App\Listener; 2 3 use Hyperf\Event\Contract\ListenerInterface; 4 use App\Event\OrderCancelled; 5 6 class OrderCancelledListener implements Listener 7 { 8 public function listen(): array 9 { 10 return [OrderCancelled::class]; 11
  32. COMPENSAÇÃO EM NESTJS COM RABBITMQ import { RabbitSubscribe } from

    '@golevelup/nest import { PaymentService } from '../services/paym import { InventoryService } from '../services/in import { NotificationService } from '../services import { LoggingService } from '../services/logg 1 import { Injectable } from '@nestjs/common'; 2 3 4 5 6 7 @Injectable() 8 export class OrderCancelledListener { 9 constructor( 10 private paymentService: PaymentService, 11 import { RabbitSubscribe } from '@golevelup/nest 1 import { Injectable } from '@nestjs/common'; 2 import { PaymentService } from '../services/paym 3 import { InventoryService } from '../services/in 4 import { NotificationService } from '../services 5 import { LoggingService } from '../services/logg 6 7 @Injectable() 8 export class OrderCancelledListener { 9 constructor( 10 private paymentService: PaymentService, 11 import { RabbitSubscribe } from '@golevelup/nest 1 import { Injectable } from '@nestjs/common'; 2 import { PaymentService } from '../services/paym 3 import { InventoryService } from '../services/in 4 import { NotificationService } from '../services 5 import { LoggingService } from '../services/logg 6 7 @Injectable() 8 export class OrderCancelledListener { 9 constructor( 10 private paymentService: PaymentService, 11
  33. CENÁRIO: Cliente está finalizando uma compra API de frete dos

    Correios está fora do ar Se não calcularmos o frete, perdemos a venda Como lidar com esse tipo de problema?
  34. IMPLEMENTAÇÃO DE CACHE #[CircuitBreaker ( options: ['timeout' => 5000], failCounter:

    3, successCounter: 1, fallback: 'processCalculateShippingFallb )] [ j ] private ShippingServiceClient $client; 10 11 12 13 14 15 16 17 18 public function processCalculateShipping($or 19 { 20 l l f d namespace App\Services; 1 2 use App\Shipping\ShippingServiceClient; 3 use Hyperf\CircuitBreaker\Annotation\CircuitBrea 4 use Hyperf\Di\Annotation\Inject; 5 6 class GatewayService 7 { 8 #[Inject] 9 private ShippingServiceClient $client; 10 11 namespace App\Services; 1 2 use App\Shipping\ShippingServiceClient; 3 use Hyperf\CircuitBreaker\Annotation\CircuitBrea 4 use Hyperf\Di\Annotation\Inject; 5 6 class GatewayService 7 { 8 #[Inject] 9 private ShippingServiceClient $client; 10 11 namespace App\Services; 1 2 use App\Shipping\ShippingServiceClient; 3 use Hyperf\CircuitBreaker\Annotation\CircuitBrea 4 use Hyperf\Di\Annotation\Inject; 5 6 class GatewayService 7 { 8 #[Inject] 9 private ShippingServiceClient $client; 10 11 namespace App\Services; 1 2 use App\Shipping\ShippingServiceClient; 3 use Hyperf\CircuitBreaker\Annotation\CircuitBrea 4 use Hyperf\Di\Annotation\Inject; 5 6 class GatewayService 7 { 8 #[Inject] 9 private ShippingServiceClient $client; 10 11 namespace App\Services; 1 2 use App\Shipping\ShippingServiceClient; 3 use Hyperf\CircuitBreaker\Annotation\CircuitBrea 4 use Hyperf\Di\Annotation\Inject; 5 6 class GatewayService 7 { 8 #[Inject] 9 private ShippingServiceClient $client; 10 11
  35. CENÁRIO PROBLEMÁTICO: MUITOS USUÁRIOS OU ATAQUE Bots fazendo scraping da

    sua loja Ataque de negação de serviço (DDoS) Pico de tráfego em promoções
  36. SOLUÇÃO: RATE LIMITING Limita o número de requisições que um

    cliente pode fazer em um período de tempo
  37. COMO FUNCIONA: Define limites por IP, usuário ou token Conta

    requisições em janelas de tempo Rejeita requisições quando o limite é atingido Retorna erro 429 (Too Many Requests) Retorna conteúdo cacheado para requisições repetidas
  38. IMPLEMENTAÇÃO EM NESTJS import { Injectable, NestMiddleware } from '@nes

    import { Request, Response, NextFunction } from import { RateLimiterRedis } from 'rate-limiter-f 1 2 3 4 @Injectable() 5 export class RateLimiterMiddleware implements Ne 6 private rateLimiter: RateLimiterRedis; 7 8 constructor() { 9 // Configuração do rate limiter 10 this.rateLimiter = new RateLimiterRedis({ 11 export class RateLimiterMiddleware implements Ne private rateLimiter: RateLimiterRedis; constructor() { import { Injectable, NestMiddleware } from '@nes 1 import { Request, Response, NextFunction } from 2 import { RateLimiterRedis } from 'rate-limiter-f 3 4 @Injectable() 5 6 7 8 9 // Configuração do rate limiter 10 this.rateLimiter = new RateLimiterRedis({ 11 this.rateLimiter = new RateLimiterRedis({ import { Injectable, NestMiddleware } from '@nes 1 import { Request, Response, NextFunction } from 2 import { RateLimiterRedis } from 'rate-limiter-f 3 4 @Injectable() 5 export class RateLimiterMiddleware implements Ne 6 private rateLimiter: RateLimiterRedis; 7 8 constructor() { 9 // Configuração do rate limiter 10 11 import { Injectable, NestMiddleware } from '@nes 1 import { Request, Response, NextFunction } from 2 import { RateLimiterRedis } from 'rate-limiter-f 3 4 @Injectable() 5 export class RateLimiterMiddleware implements Ne 6 private rateLimiter: RateLimiterRedis; 7 8 constructor() { 9 // Configuração do rate limiter 10 this.rateLimiter = new RateLimiterRedis({ 11 import { Injectable, NestMiddleware } from '@nes 1 import { Request, Response, NextFunction } from 2 import { RateLimiterRedis } from 'rate-limiter-f 3 4 @Injectable() 5 export class RateLimiterMiddleware implements Ne 6 private rateLimiter: RateLimiterRedis; 7 8 constructor() { 9 // Configuração do rate limiter 10 this.rateLimiter = new RateLimiterRedis({ 11
  39. BENEFÍCIOS DO RATE LIMITING Protege contra ataques de força bruta

    Evita que um único cliente monopolize recursos Mantém o sistema disponível para todos os usuários Reduz custos de infraestrutura Equilibra as cargas para um serviço mais justo
  40. OPEN/CLOSED PRINCIPLE Princípio Aberto/Fechado do SOLID "Entidades de software devem

    estar abertas para extensão, mas fechadas para modificação." Em outras palavras: adicione comportamentos sem mexer no código existente
  41. INTERFACE E IMPLEMENTAÇÕES // Interface comum para todos os provedores

    de f interface ShippingProviderInterface { /** * Calcula o frete para um pedido */ public function calculateShipping(array $ord public function trackShipment(string $tracki public function getName(): string; } 1 2 3 4 5 6 7 8 9 10 11 // Interface comum para todos os provedores de f 1 interface ShippingProviderInterface 2 { 3 /** 4 * Calcula o frete para um pedido 5 */ 6 public function calculateShipping(array $ord 7 public function trackShipment(string $tracki 8 public function getName(): string; 9 } 10 11 // Interface comum para todos os provedores de f 1 interface ShippingProviderInterface 2 { 3 /** 4 * Calcula o frete para um pedido 5 */ 6 public function calculateShipping(array $ord 7 public function trackShipment(string $tracki 8 public function getName(): string; 9 } 10 11 // Interface comum para todos os provedores de f 1 interface ShippingProviderInterface 2 { 3 /** 4 * Calcula o frete para um pedido 5 */ 6 public function calculateShipping(array $ord 7 public function trackShipment(string $tracki 8 public function getName(): string; 9 } 10 11
  42. UTILIZANDO A FACTORY $factory = new ShippingProviderFactory(); // Configuração da

    aplicação 1 2 3 // Registramos todos os provedores disponíveis 4 $factory->registerProvider(new CorreiosShippingP 5 $factory->registerProvider(new FastShippingProvi 6 // Podemos adicionar novos provedores aqui sem m 7 $factory->registerProvider(new InternationalShip 8 9 // Cliente escolhe qual provedor usar 10 $providerName = $_POST['shipping_provider'] ?? 11 // Registramos todos os provedores disponíveis $factory->registerProvider(new CorreiosShippingP $factory->registerProvider(new FastShippingProvi // Podemos adicionar novos provedores aqui sem m $factory->registerProvider(new InternationalShip // Configuração da aplicação 1 $factory = new ShippingProviderFactory(); 2 3 4 5 6 7 8 9 // Cliente escolhe qual provedor usar 10 $providerName = $_POST['shipping_provider'] ?? 11 // Cliente escolhe qual provedor usar $providerName = $_POST['shipping_provider'] ?? // Configuração da aplicação 1 $factory = new ShippingProviderFactory(); 2 3 // Registramos todos os provedores disponíveis 4 $factory->registerProvider(new CorreiosShippingP 5 $factory->registerProvider(new FastShippingProvi 6 // Podemos adicionar novos provedores aqui sem m 7 $factory->registerProvider(new InternationalShip 8 9 10 11 // Configuração da aplicação 1 $factory = new ShippingProviderFactory(); 2 3 // Registramos todos os provedores disponíveis 4 $factory->registerProvider(new CorreiosShippingP 5 $factory->registerProvider(new FastShippingProvi 6 // Podemos adicionar novos provedores aqui sem m 7 $factory->registerProvider(new InternationalShip 8 9 // Cliente escolhe qual provedor usar 10 $providerName = $_POST['shipping_provider'] ?? 11
  43. BENEFÍCIOS DO OPEN/CLOSED PRINCIPLE Código mais estável e menos propenso

    a bugs Podemos adicionar novos provedores sem risco Testes existentes continuam válidos Facilita a manutenção e a extensão do sistema Aplicando SOLID, ganhamos resiliência e flexibilidade.
  44. FALLBACKS Planos B para quando algo falha, oferecendo alternativas em

    vez de deixar a operação falhar completamente.
  45. CACHE + VALORES DEFAULT Armazenar resultados de operações para uso

    quando serviços externos estiverem indisponíveis, melhorando disponibilidade.
  46. RATE LIMITING Limitar o número de requisições que um cliente

    pode fazer em um período, protegendo contra abusos e distribuindo recursos de forma justa.
  47. PRÓXIMOS PASSOS Estude mais sobre padrões de resiliência Implemente esses

    conceitos em seus projetos Participe de comunidades e compartilhe experiências
  48. CONCLUSÃO Falhas são inevitáveis Sistemas resilientes prevêm e se adaptam

    a falhas Combine diferentes padrões para maior robustez A resiliência deve ser parte do design inicial Projete para falhar!