encore-cache

Par encoredev · skills

Mettez en cache des données dans Redis depuis Encore.ts en utilisant `CacheCluster` et des keyspaces typés issus de `encore.dev/storage/cache`. Accès clé/valeur type-safe avec TTL, incréments atomiques et structures de données par keyspace.

npx skills add https://github.com/encoredev/skills --skill encore-cache

Cache Encore (Redis)

Instructions

Le cache d'Encore est un wrapper typé autour de Redis. Déclarez une CacheCluster une fois, puis créez des objets Keyspace pour chaque forme de données dont vous avez besoin.

Cluster

import { CacheCluster } from "encore.dev/storage/cache";

const cluster = new CacheCluster("my-cache", {
  evictionPolicy: "allkeys-lru",
});

Référencez un cluster depuis un autre service : const cluster = CacheCluster.named("my-cache");

Politiques d'éviction : "allkeys-lru" (par défaut), "noeviction", "allkeys-lfu", "allkeys-random", "volatile-lru", "volatile-lfu", "volatile-ttl", "volatile-random".

Types de keyspace

Chaque keyspace a une forme de clé (utilisée pour construire la clé Redis à partir de keyPattern) et un type de valeur.

import {
  StringKeyspace,
  IntKeyspace,
  FloatKeyspace,
  StructKeyspace,
  StringListKeyspace,
  NumberListKeyspace,
  StringSetKeyspace,
  NumberSetKeyspace,
  expireIn,
} from "encore.dev/storage/cache";

// Strings
const tokens = new StringKeyspace<{ tokenId: string }>(cluster, {
  keyPattern: "token/:tokenId",
  defaultExpiry: expireIn(3600 * 1000),
});
await tokens.set({ tokenId: "abc" }, "value");
const val = await tokens.get({ tokenId: "abc" }); // undefined on miss

// Integers (atomic counters)
const counters = new IntKeyspace<{ userId: string }>(cluster, {
  keyPattern: "requests/:userId",
  defaultExpiry: expireIn(10 * 1000),
});
const count = await counters.increment({ userId: "user123" }, 1);

// Structs (JSON)
interface UserProfile { name: string; email: string; }
const profiles = new StructKeyspace<{ userId: string }, UserProfile>(cluster, {
  keyPattern: "profile/:userId",
  defaultExpiry: expireIn(3600 * 1000),
});
await profiles.set({ userId: "123" }, { name: "Alice", email: "alice@example.com" });

// Lists
const recent = new StringListKeyspace<{ userId: string }>(cluster, {
  keyPattern: "recent/:userId",
});
await recent.pushRight({ userId: "user123" }, "item1", "item2");

// Sets
const tags = new StringSetKeyspace<{ articleId: string }>(cluster, {
  keyPattern: "tags/:articleId",
});
await tags.add({ articleId: "post1" }, "typescript", "encore");
const has = await tags.contains({ articleId: "post1" }, "typescript");

Motifs de clé multi-champs

interface Key { userId: string; resourcePath: string; }

const requests = new IntKeyspace<Key>(cluster, {
  keyPattern: "requests/:userId/:resourcePath",
  defaultExpiry: expireIn(10 * 1000),
});

Assistants d'expiration

import {
  expireIn,          // milliseconds
  expireInSeconds,
  expireInMinutes,
  expireInHours,
  expireDailyAt,     // a specific UTC time each day
  neverExpire,
  keepTTL,           // keep existing TTL when updating
} from "encore.dev/storage/cache";

Options d'écriture

await keyspace.set(key, value, { expiry: expireInMinutes(30) });
await keyspace.set(key, value, { expiry: keepTTL });
await keyspace.setIfNotExists(key, value);  // throws CacheKeyExists if present
await keyspace.replace(key, value);          // throws CacheMiss if absent

Erreurs

import { CacheMiss, CacheKeyExists } from "encore.dev/storage/cache";

const value = await keyspace.get(key);  // undefined on miss (does not throw)

Recommandations

  • Déclarez CacheCluster et les keyspaces au niveau du package.
  • Choisissez le type de keyspace le plus spécifique — IntKeyspace pour les compteurs vous offre gratuitement les opérations atomiques increment/decrement.
  • get() retourne undefined en cas d'absence ; replace() et setIfNotExists() lèvent une exception en cas de conflit.
  • Le développement local utilise une Redis en mémoire avec une limite d'environ 100 clés — ne la testez pas en charge.
  • Pour le stockage durable, utilisez encore-database (Postgres) ou encore-bucket (stockage objet) à la place.

Skills similaires