Saltar al contenido principal

Caché

Vali-Mediator.Caching agrega caché declarativa en el pipeline a cualquier IRequest<T> sin modificar el código del handler — incluye coalescing automático de misses concurrentes, así una estampida de requests idénticos ejecuta el handler una sola vez.

Instalación​

dotnet add package Vali-Mediator.Caching

Configuración​

builder.Services.AddValiMediator(config =>
{
config.RegisterServicesFromAssemblyContaining<Program>();
config.AddCachingBehavior();
});

builder.Services.AddInMemoryCacheStore();

Cómo Funciona​

loading...

Ejemplo Rápido​

public record GetProductQuery(Guid Id)
: IRequest<Result<ProductDto>>, ICacheable
{
public string CacheKey => $"product:{Id}";
public TimeSpan? AbsoluteExpiration => TimeSpan.FromMinutes(10);
public TimeSpan? SlidingExpiration => null;
public string? CacheGroup => "products";
public bool BypassCache => false;
public CacheOrder Order => CacheOrder.ReadThenWrite;
}

El handler no necesita cambios — la caché se aplica transparentemente por el pipeline behavior.

Conceptos Clave​

ConceptoDescripción
ICacheableMarca una solicitud como cacheable; provee clave de caché y expiración
IInvalidatesCacheMarca una solicitud que invalida entradas cacheadas
ICacheStoreAbstracción del backend de caché (en memoria, Redis, etc.)
CacheOrderControla check-then-store vs store-only vs check-only
CacheGroupAgrupa entradas de caché relacionadas para invalidación masiva

Coalescing de Misses Concurrentes​

Cuando varios requests piden la misma clave de caché al mismo tiempo y es un miss, solo el primero ejecuta el handler — el resto espera ese mismo resultado en vuelo en lugar de golpear cada uno el backing store (y, transitivamente, la base de datos). Esto es automático con AddCachingBehavior() registrado; la única perilla es cuánto espera un seguidor antes de desistir y correr el handler por su cuenta:

builder.Services.AddCachingOptions(options =>
{
options.CoalescingWaitTimeout = TimeSpan.FromSeconds(30); // limita el daño de un handler colgado
});

Límites del Store en Memoria​

Todo límite se valida (debe ser mayor a cero) y acota la memoria incluso cuando las claves/grupos vienen de input controlado por el cliente — una clave sobredimensionada o un grupo que supera el límite se descarta en lugar de aceptarse:

builder.Services.AddInMemoryCacheStore(options =>
{
options.MaxEntries = 10_000; // se expulsa la entrada menos usada recientemente al llenarse
options.MaxKeyLength = 512; // claves/nombres de grupo más largos nunca se almacenan
options.MaxGroups = 10_000; // grupos distintos indexados a la vez
options.MaxKeysPerGroup = 10_000; // claves indexadas bajo un grupo
options.CleanupInterval = TimeSpan.FromMinutes(5);
});