logo hsb.horse
← Retour à l’index des snippets

Snippets

Pattern d'orchestration cache d'abord, récupération en direct ensuite

Orchestration combinant un chemin rapide depuis le cache et un chemin lent depuis un service distant. Mesure les hits/miss de cache, la latence et le résultat final sous forme de métriques, en déléguant les effets de bord vers l'extérieur.

Publié: Mis à jour:

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 à MetricsReporter dé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.