Pular para o conteúdo

Fallback

Falhas parciais são inevitáveis: um serviço de recomendações caiu, o de preços está lento, o Circuit Breaker abriu. Sem tratamento, essa falha sobe até o usuário como um erro 500, mesmo que a funcionalidade principal ainda funcione. Muitas vezes a dependência é não-crítica — a página de produto pode ser renderizada sem o bloco de “recomendados”. O fallback decide o que servir quando o caminho feliz não está disponível.

Definir, para cada chamada que pode falhar, uma resposta alternativa invocada quando a chamada principal lança exceção ou é barrada pelo circuit breaker. Estratégias comuns, da melhor à mais pobre:

  • Cache: retornar o último valor conhecido (stale-but-usable). Ideal para dados que mudam pouco.
  • Valor default / vazio: lista de recomendações vazia, frete “a calcular”, flag desligada.
  • Funcionalidade reduzida: servir uma versão simplificada (ex.: busca sem ranking personalizado).
  • Fonte secundária: um serviço/replica alternativo.
  • Falha explícita e honesta: quando não há alternativa segura, uma mensagem clara (“recomendações indisponíveis”) é melhor que dados errados.

O fallback só faz sentido para dependências não-críticas ao caso de uso. Para uma dependência crítica (ex.: autorização de pagamento numa compra), não invente um fallback que finja sucesso — falhe de forma segura. Servir dado errado pode ser pior que servir erro.

  • Prós: mantém disponibilidade percebida, isola falhas de dependências não-críticas, melhora a experiência.
  • Contras: pode servir dados desatualizados (cache stale) e mascarar problemas reais (o incidente fica invisível se o fallback for silencioso). Fallbacks precisam de observabilidade — métricas/logs de quantas vezes foram acionados.
  • Em dependências críticas onde uma resposta falsa é perigosa (pagamento, autorização, saldo).
  • Quando não existe alternativa segura e significativa — melhor falhar explicitamente.
  • Quando o fallback esconde falhas que precisam de ação imediata sem gerar alertas.

Fallback combinado com Circuit Breaker: quando o circuito abre ou a chamada falha, serve cache; se não houver cache, lista vazia.

@Service
@RequiredArgsConstructor
public class RecommendationService {
private final RecommendationClient client;
private final RecommendationCache cache;
@CircuitBreaker(name = "recommendations", fallbackMethod = "fromCacheOrEmpty")
public List<Product> recommend(UUID userId) {
var result = client.fetchRecommendations(userId);
cache.put(userId, result);
return result;
}
private List<Product> fromCacheOrEmpty(UUID userId, Throwable ex) {
log.warn("Fallback de recomendações para user={} causa={}",
userId, ex.toString());
recommendationFallbackCounter.increment();
return cache.get(userId).orElseGet(List::of);
}
}

A assinatura do fallbackMethod deve casar com o método original mais o Throwable no fim. Note o incremento de uma métrica: o fallback é observável, não silencioso.

sequenceDiagram
    participant UI as Página de Produto
    participant Svc as RecommendationService
    participant Rec as Serviço de Recomendações
    participant Cache
    UI->>Svc: recommend(userId)
    Svc->>Rec: fetchRecommendations(userId)
    Rec-->>Svc: erro / timeout (circuito aberto)
    Note over Svc: aciona fallbackMethod
    Svc->>Cache: get(userId)
    Cache-->>Svc: último valor conhecido (ou vazio)
    Svc-->>UI: recomendações degradadas
    Note over UI: página renderiza sem erro
  • Fallback silencioso: engolir a exceção sem métrica/log — o incidente fica invisível e ninguém corrige a causa.
  • Fallback em dependência crítica fingindo sucesso: aprovar um pagamento que na verdade falhou é catastrófico.
  • Fallback que também depende do serviço quebrado: cache no mesmo serviço que caiu não ajuda.
  • Fallback com lógica pesada que pode falhar por conta própria: mantenha-o simples e rápido.
  • Cache stale sem limite de idade: servir dado antigo demais como se fosse atual, sem sinalizar.
  1. O que é degradação graciosa e como o fallback a implementa?
Resposta

É manter o sistema utilizável mesmo com partes indisponíveis, oferecendo uma experiência reduzida em vez de um erro total. O fallback a implementa ao substituir a resposta de uma dependência falha por uma alternativa (cache, default, versão simplificada), permitindo que o fluxo principal continue.

  1. Por que fallbacks não devem ser silenciosos?
Resposta

Porque mascaram o problema real: se o fallback engole a exceção sem métrica nem log, o incidente fica invisível e ninguém corrige a causa raiz. Fallbacks precisam ser observáveis — contadores e alertas — para que a equipe saiba com que frequência estão sendo acionados.

  1. Em que situação NÃO se deve usar fallback?
Resposta

Em dependências críticas onde uma resposta alternativa seria enganosa ou perigosa — pagamento, autorização, verificação de saldo. Fingir sucesso nesses casos é pior que falhar. Também não se deve usar quando não há alternativa segura e significativa: melhor falhar de forma explícita e honesta.

  1. Como fallback, retry e circuit breaker se encaixam numa mesma chamada?
Resposta

O Retry tenta absorver falhas transitórias; se persistem, o Circuit Breaker abre e passa a barrar chamadas rapidamente; enquanto o circuito está aberto (ou quando os retries esgotam), o fallback fornece a resposta degradada. Juntos cobrem falha transitória, falha persistente e a experiência do usuário durante a indisponibilidade.