Skip to content

[API Proposal]: [HybridCache] Add backplane support for cross-pod L1 cache invalidation #125602

Description

@yanxiaodi

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions