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
MetricsReporterdesacopla 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.
hsb.horse