extensions icon indicating copy to clipboard operation
extensions copied to clipboard

[API Proposal]: HybridCache - should a HC-backed IDistributedCache be offered?

Open mgravell opened this issue 1 year ago • 0 comments

Background and motivation

Currently, HybridCache optionally consumes IDistributedCache (and IBufferDistributedCache via type-testing) as the L2 backend, typically for out-of-process/off-box storage (Redis etc).

A lot of existing code consumes IDistributedCache, and while in a perfect world they would migrate to HybridCache, we do not live in a perfect world, so there is a question as to whether it may be useful to optionally offer an IDistributedCache that is, effectively, a L1+L2 wrapper.

Considerations

  • this option is only relevant when using L1+L2 (i.e. a non-trivial IDistributedCache backend); if you only want L1, there is already AddDistributedMemoryCache which does exactly that
  • this would require careful configuration, to disambiguate the optional out-of-proc IDistributedCache backend from the exposed backend - this could be either via keyed-DI, or via explicit configuration against the HybridCacheOptions
    • further: many existing backends do not currently readily offer either a keyed-DI config, or a direct factory method; for example, AddStackExchangeRedisCache only works on the default DI; maybe one option there is for the new exposed DI to be keyed?
    • see also keyed service topic here: https://github.com/dotnet/runtime/issues/109017
  • the API would be different and would not have full feature parity, since IDistributedCache has separate get/put APIs - this is manageable, however
  • for correctness guarantees, we would need to perform defensive byte[] copies when using IDistributedCache, but that doesn't present a significant change - that is already expected
  • if done, it is easy to also support IBufferDistributedCache (and we should do so), although should not expect massive usage; the entire point of things like HybridCache is to make that a non-concern for application code

Usage example

(entirely speculative and open to discussion)

// existing L2 registraction
services.AddStackExchangeRedisCache(...); // some L2

//  existing service usage
public SomeService(IDistributedCache cache)
{
    public async Task SomeMethodAsync()
    {
        // blah, cache.GetAsync etc
    }
}

// new registration
services.AddHybridCache(...).WithKeyedDistributedCache("some key");

with the change to existing usage consisting of:

- public SomeService(IDistributedCache cache)
+ public SomeService([FromKeyedServices("some key")] IDistributedCache cache)

The downside of this is that it still requires per-usage changes, but that may be desirable anyway, to ensure the usage is fully considered.

Questions

  • is this whole thing needed?
  • is there a better way of handling the two separate IDistributedCache uses, that works better?
  • should the key be defaulted to something like typeof(HybridCache) if not specified, or is that silly?

mgravell avatar Oct 18 '24 13:10 mgravell