Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability to set CacheSettings depending on the result of the valueFactory #215

Open
celluj34 opened this issue Dec 14, 2022 · 4 comments
Open
Labels
enhancement New feature or request

Comments

@celluj34
Copy link

What problem does the feature solve?

I would like to be able to set the CacheSettings depending on the result of some logic that's run in the valueFactory of the GetOrSetAsync method. This would function similarly to the IMemoryCache.GetOrCreateAsync provided by Microsoft.

The reason this is important to me is, when an exception is thrown, or some logic fails inside the valueFactory, I want the data to not be cached.

How would you use/interact with the feature? (if applicable)

var result = await _cache.GetOrSetAsync<EntityResult<DataModel>>(key,
  async entry =>
  {
    try
    {
      var data = await GetData(model);

      entry.AbsoluteExpirationRelativeToNow = _cacheTimeSpan;

      return new EntityResult<DataModel>(data);
    }
    catch (Exception ex)
    {
      entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromTicks(1);

      return new EntityResult<DataModel>().AddError(ex);
    }
  });

How would you call it in your own code?

See code sample above

Are there constraints that would need to be in place with this feature?

None that can think of - it may be a breaking change, or change how the stacks work.

If I misunderstand how I'm supposed to use this, please let me know. We only do it this way because of some bugs we had where the valueFactorys were being run more than once when the database methods threw an exception.

@celluj34 celluj34 added the enhancement New feature or request label Dec 14, 2022
@Turnerj
Copy link
Member

Turnerj commented Dec 18, 2022

Hey @celluj34 - thanks for raising this feature request! Sounds like a perfectly reasonable idea - currently I propagate the exception because I didn't like the idea of swallowing by default however having some mechanism to selectively skip that would be pretty useful.

I've got an idea of how I might be able to do something to support this with a fluent-like API which might be an easier path forward than passing control to within the value factory itself but either way, being able to opt-out of exceptions being bubbled up is a useful feature to have.

@celluj34
Copy link
Author

celluj34 commented Dec 18, 2022

Another thought I had, what about adding an overload for the CacheSettings parameters that takes a Func<T, CacheSettings>? Then we could decide how to set based on the value generator. Or maybe all of the above! Just throwing that out there.

@celluj34 celluj34 reopened this Dec 18, 2022
@celluj34
Copy link
Author

Sorry hit the wrong button!

@cezarlamann
Copy link

+1 on this for caching Authentication (bearer) tokens which have their expiration time coming on the object that returns from auth endpoints.

It would be something like this (I tried rolling out my own methods of Redis Caching, using RedLock for synchronization between Redis Nodes, not sure if it would work):

        public async Task<T> GetOrAddAsync<T>(string key, Func<T> itemCreationFunc, Func<T, TimeSpan> itemBasedExpiryFunc)
        {
            if (key == null) throw new ArgumentNullException(nameof(key));

            var bytes = await _distributedCache.GetAsync(key);

            if (bytes != null)
            {
                return JsonSerializer.Deserialize<T>(bytes.AsSpan()) ?? Activator.CreateInstance<T>();
            }

            using (var redLock = await _distributedLockFactory.CreateLockAsync($"redis-cache-lock-key-{key}", TimeSpan.FromSeconds(5)))
            {
                var obj = itemCreationFunc();
                var serializedObj = JsonSerializer.SerializeToUtf8Bytes(obj);
                var expiration = itemBasedExpiryFunc(obj);
                _distributedCache.Set(key, serializedObj, new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = expiration });
                return obj;
            }
        }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants