En combinant cache et récupération distante, la logique a tendance à se mêler. Encapsuler le tout dans une fonction d’orchestration permet de séparer clairement les chemins de succès et d’échec du cache, tout en centralisant l’instrumentation des métriques et la délégation des effets de bord.
Définitions des types
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;}Fonction d’orchestration
async function orchestrate<T>( key: string, cache: CacheProvider<T>, remote: RemoteProvider<T>, metrics: MetricsReporter,): Promise<T> { const start = performance.now();
// Chemin rapide : hit de cache const cached = await cache.get(key); if (cached !== undefined) { metrics.recordCacheHit(key, performance.now() - start); return cached; }
// Chemin lent : récupération en direct metrics.recordCacheMiss(key); const fetchStart = performance.now(); try { const data = await remote.fetch(key); metrics.recordFetchLatency(key, performance.now() - fetchStart);
// Effet de bord délégué vers l'extérieur — 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; }}Exemple d’utilisation
const result = await orchestrate( 'user:42', redisCache, userApiClient, datadogMetrics,);Explication
- Chemin rapide : Si le cache est trouvé, retour immédiat — le service distant n’est jamais appelé.
- Chemin lent : Repli vers le service distant uniquement en cas de miss. Après la récupération, le cache est mis à jour en fire-and-forget.
- Métriques : Hits, miss, latence de récupération et résultat final sont tous instrumentés. La délégation à
MetricsReporterdécouple l’orchestrateur de Datadog, Prometheus ou tout autre backend de logs. - Délégation des effets de bord : Les écritures en cache et les appels de métriques sont externalisés. Cela simplifie les tests unitaires et facilite le remplacement des implémentations.
Applications
Ce pattern convient particulièrement pour :
- Importateurs : Passer rapidement les enregistrements déjà traités avant d’appeler la source.
- Jobs d’enrichissement de données : Éviter de ré-enrichir des entités déjà complètes.
- Gestionnaires de synchronisation : Prévenir les récupérations en double tout en suivant les différences avec des métriques.
- Actions UI coûteuses : Exécuter l’appel distant uniquement au premier chargement ; servir les requêtes suivantes depuis le cache.
Comme CacheProvider, RemoteProvider et MetricsReporter sont définis comme des interfaces, n’importe quelle combinaison d’implémentations — Redis/in-memory, REST/gRPC, Datadog/StatsD — peut être branchée sans modifier la logique d’orchestration.
hsb.horse