Background and motivation
HybridCache has no mechanism to invalidate L1 (in-process memory) entries on other nodes/pods when a cache entry is written or removed. In a multi-pod deployment, this means L1 caches across pods can serve stale data for the entire L1 TTL duration, even after a RemoveAsync or a forced refresh.
HybridCache pairs a fast in-process L1 cache (e.g. MemoryCache) with a shared L2 distributed cache (e.g. Redis). A call to RemoveAsync("some-key") on pod A correctly removes the entry from L2 (Redis) and from pod A's L1 — but the same key may still be alive in pods B, C, D… until their L1 TTL naturally expires.
This makes it impossible to honour cache-busting semantics across a cluster. For example, if a consumer sends Cache-Control: no-cache and the application fetches fresh data and stores it back, subsequent requests hitting other pods will still return the stale L1-cached value for up to the full L1 TTL. Or when an operation needs to reset the cache but it can only reset the cache on this pod.
API Proposal
A backplane abstraction that allows pluggable implementations (Redis pub/sub, ServiceBus, SignalR backplane, etc.):
// New interface in Microsoft.Extensions.Caching.Hybrid
public interface IHybridCacheBackplane
{
ValueTask PublishInvalidationAsync(string key, CancellationToken token = default);
// Called by DefaultHybridCache when an L1 entry should be evicted
void Subscribe(Action<string> onInvalidate);
}
DefaultHybridCache would call PublishInvalidationAsync after every RemoveAsync / SetAsync, and each pod's subscription callback would call MemoryCache.Remove(key) on its own L1.
API Usage
A first-party Redis implementation would be a natural fit alongside the existing Microsoft.Extensions.Caching.StackExchangeRedis package:
// New extension method
builder.Services.AddHybridCache()
.AddRedisBackplane(options =>
options.Configuration = "localhost:6379");
This would reuse the existing IConnectionMultiplexer registration (if present) to avoid a second Redis connection.
Notes:
- Redis is already a required dependency for L2 in most real-world deployments, so a Redis-based backplane would add no new infrastructure dependency for the majority of users.
StackExchange.Redis already supports pub/sub on the same IConnectionMultiplexer; Microsoft.AspNetCore.SignalR Redis backplane follows the same pattern.
Alternative Designs
No response
Risks
No response
Background and motivation
HybridCachehas no mechanism to invalidate L1 (in-process memory) entries on other nodes/pods when a cache entry is written or removed. In a multi-pod deployment, this means L1 caches across pods can serve stale data for the entire L1 TTL duration, even after aRemoveAsyncor a forced refresh.HybridCachepairs a fast in-process L1 cache (e.g.MemoryCache) with a shared L2 distributed cache (e.g. Redis). A call toRemoveAsync("some-key")on pod A correctly removes the entry from L2 (Redis) and from pod A's L1 — but the same key may still be alive in pods B, C, D… until their L1 TTL naturally expires.This makes it impossible to honour cache-busting semantics across a cluster. For example, if a consumer sends
Cache-Control: no-cacheand the application fetches fresh data and stores it back, subsequent requests hitting other pods will still return the stale L1-cached value for up to the full L1 TTL. Or when an operation needs to reset the cache but it can only reset the cache on this pod.API Proposal
A backplane abstraction that allows pluggable implementations (Redis pub/sub, ServiceBus, SignalR backplane, etc.):
DefaultHybridCachewould callPublishInvalidationAsyncafter everyRemoveAsync/SetAsync, and each pod's subscription callback would callMemoryCache.Remove(key)on its own L1.API Usage
A first-party Redis implementation would be a natural fit alongside the existing
Microsoft.Extensions.Caching.StackExchangeRedispackage:This would reuse the existing
IConnectionMultiplexerregistration (if present) to avoid a second Redis connection.Notes:
StackExchange.Redisalready supports pub/sub on the sameIConnectionMultiplexer;Microsoft.AspNetCore.SignalRRedis backplane follows the same pattern.Alternative Designs
No response
Risks
No response