logo hsb.horse
← Voltar para o índice de snippets

Snippets

Padrão de Orquestração Cache-First, Live-Fetch

Orquestração que combina um caminho rápido pelo cache com um caminho lento pelo serviço remoto. Mede hits/misses de cache, latência e resultado final como métricas, delegando os efeitos colaterais para fora.

Publicado: Atualizado:

Ao combinar cache com busca remota, a lógica tende a se misturar. Encapsular tudo em uma função de orquestração mantém os caminhos de hit e miss do cache limpos, centralizando a instrumentação de métricas e a delegação de efeitos colaterais.

Definições de Tipos

interface CacheProvider<T> {
get(key: string): Promise<T | undefined>;
set(key: string, value: T): Promise<void>;
}
interface RemoteProvider<T> {
fetch(key: string): Promise<T>;
}
interface MetricsReporter {
recordCacheHit(key: string, latencyMs: number): void;
recordCacheMiss(key: string): void;
recordFetchLatency(key: string, latencyMs: number): void;
recordOutcome(key: string, outcome: 'success' | 'error', latencyMs: number): void;
}

Função de Orquestração

async function orchestrate<T>(
key: string,
cache: CacheProvider<T>,
remote: RemoteProvider<T>,
metrics: MetricsReporter,
): Promise<T> {
const start = performance.now();
// Caminho rápido: cache hit
const cached = await cache.get(key);
if (cached !== undefined) {
metrics.recordCacheHit(key, performance.now() - start);
return cached;
}
// Caminho lento: live fetch
metrics.recordCacheMiss(key);
const fetchStart = performance.now();
try {
const data = await remote.fetch(key);
metrics.recordFetchLatency(key, performance.now() - fetchStart);
// Efeito colateral delegado para fora — fire and forget
void cache.set(key, data);
metrics.recordOutcome(key, 'success', performance.now() - start);
return data;
} catch (error) {
metrics.recordOutcome(key, 'error', performance.now() - start);
throw error;
}
}

Exemplo de Uso

const result = await orchestrate(
'user:42',
redisCache,
userApiClient,
datadogMetrics,
);

Explicação

  • Caminho rápido: Se o cache for encontrado, retorna imediatamente — o serviço remoto nunca é chamado.
  • Caminho lento: Retrocede para o serviço remoto apenas em caso de miss. Após a busca, o cache é atualizado como efeito colateral fire-and-forget.
  • Métricas: Hits, misses, latência de busca e resultado final são todos instrumentados. Delegar para MetricsReporter desacopla o orquestrador do Datadog, Prometheus ou qualquer outro backend de logs.
  • Delegação de efeitos colaterais: Escritas no cache e chamadas de métricas são externalizadas. Isso facilita os testes unitários e simplifica a troca de implementações.

Aplicações

Este padrão se encaixa bem para:

  • Importadores: Pular registros já processados com uma verificação rápida no cache antes de chamar a fonte.
  • Jobs de enriquecimento de dados: Evitar re-enriquecer entidades já completas.
  • Handlers de sincronização: Prevenir buscas duplicadas enquanto rastreia diferenças com métricas.
  • Ações de UI custosas: Executar a chamada remota apenas no primeiro carregamento; servir requisições subsequentes do cache.

Como CacheProvider, RemoteProvider e MetricsReporter são definidos como interfaces, qualquer combinação de implementações — Redis/in-memory, REST/gRPC, Datadog/StatsD — pode ser conectada sem alterar a lógica de orquestração.