[FEATURE] Key-dependent cache entry options #367
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Hi, I was not sure about the exact flow for the feature request/PR, so I decided to just create the PR directly. Let me know, if I need to create a corresponding issue and link it to this PR 😄
Problem
I want to be able to configure individual cache entry options for a given subset of keys (e.g., all keys, starting with "foo-") in a generic manner, that is, via standard IOptions mechanism, provided by Microsoft out of the box. This is beneficial for:
Currently, only the default entry options are exposed, which means I can only setup them for all entries. However, if I want to setup entry options in a more granular manner, I need to resort to adjusting the code at the call site, providing modified options argument.
Solution
Provide new FusionCacheOptions.KeyDependentEntryOptions property, that applies options per cache key template:
Also, provide a public IKeyedFusionCacheEntryOptionsProvider interface, so that custom key lookup strategy can be used.
By default, the KeyPrefixBasedEntryOptionsProvider is used to select the corresponding options. It returns the entry options for the longest matching prefix for the given cache key. If no options are found, DefaultEntryOptions are returned.
On every cache operation that involves the cache key, get the entry options from the following sources, until one is found:
expliticly provided entry options -> key-dependent entry options -> default entry options
Public API updates
Two built-in implementations for the interface are provided: KeyPrefixBasedEntryOptionsProvider and NullKeyedEntryOptionsProvider.
FusionCacheEntryOptions FusionCache.CreateEntryOptions(string key, Action<FusionCacheEntryOptions>? setupAction = null, TimeSpan? duration = null)
has been added as an addition to the existing one, that doesn't accept the key. I'm not sure if it makes sense to mark the existing one as Obsolete, since it is no longer used. I kept it as is for now.IFusionCacheBuilder WithKeyDependentEntryOptionsProvider(this IFusionCacheBuilder builder, Action<CustomServiceRegistration<IKeyedFusionCacheEntryOptionsProvider>> config)
extension method to setup custom IKeyedFusionCacheEntryOptionsProvider provider.Implementation details and limitations
The current implementation of KeyPrefixBasedEntryOptionsProvider is instantiated upon FusionCache creation, which means later updates to the KeyPrefixBasedEntryOptions members will have only limited effect. That is, changes to the entry options themselves will be applied, however it is not possible to add or remove mappings, or adjust key templates for mappings after cache creation.
Default KeyPrefixBasedEntryOptionsProvider does not support multiple configurations for the same prefix: the internal .ToDictionary() call will throw on multiple entries with the same KeyTemplate. This is done on purpose, to avoid unexpected behavior and hard-to-track bugs later at runtime.
Current prefix search algorithm is a simple binary search among the pre-sorted array of prefixes. Assuming the amount of mappings will stay reasonably small, it shouldn't give too much of an overhead. Otherwise a better data structure, e.g., prefix tree can be assumed. Also, when key-dependent options are not set (that is the case for all existing setups), the only overhead is an additional length + null check, which should be negligible.
IMPORTANT: keys are considered exactly as they are passed in to the public APIs, that is before applying the CacheKeyPrefix adjustment. The reason for this is that CacheKeyPrefix is set up only once for the entire cache, so it is expected to stay the same for all keys.
PS The PR is pretty big, sorry for that. Luckily, the majority of changes are to the XML comments 😸
Also, the project itself is already very nicely structured, so incorporating the options selection fits in perfectly in the existing APIs, without affecting any lower-level caching logic.
And thank you once again for the awesome library! 🚀