ZiggyCreatures / FusionCache

FusionCache is an easy to use, fast and robust hybrid cache with advanced resiliency features.
MIT License
1.56k stars 84 forks source link

[FEATURE] Allow the factory to determine the cache duration? #252

Closed onionhammer closed 1 month ago

onionhammer commented 1 month ago

Problem

Often times the factory will tell you how long something should be cached for, but unless I'm not seeing it/it's not obvious, I don't believe FusionCache provides a way (like built in MemoryCache) to set an expiration within the factory method.

Example:

var authToken = await cache.GetOrSetAsync("MyCachedToken", async ct =>
{
    var context = new TokenRequestContext([...]);
    var response = await tokenCredential.GetTokenAsync(context, ct);

    // expiration is in the `response.ExpiresOn`
}, options => option.SetDurationMs(300) /* ExpiresOn inaccessible here */);

Solution

Add a second overload to "GetOrSetAsync" and others which provides a second parameter to the cancellation token which lets the factory set the expiration

i.e.

var authToken = await cache.GetOrSetAsync("MyCachedToken", async (entry, cancellationToken) =>
{
    var context  = new TokenRequestContext([...]);
    var response = await tokenCredential.GetTokenAsync(context, cancellationToken);

    entry.AbsoluteExpiration = response.ExpiresOn - TimeSpan.FromSeconds(60);

    return response.Token;
}, static options => options
    // .SetDuration(TimeSpan.FromSeconds(30))
    .SetSkipDistributedCache(skip: true, skipBackplaneNotifications: true)
);

Alternatives

Use IMemoryCache instead

onionhammer commented 1 month ago

Update: Ok, actually I think I found it? Only available if you explicitly set the generic argument

// Add the Azure Maps token to the request
var authToken = await cache.GetOrSetAsync<string>("MyCachedToken", async (ctx, cancellationToken) =>
{
    var context  = new TokenRequestContext([...]);
    var response = await tokenCredential.GetTokenAsync(context, cancellationToken);

    ctx.Options.SetDuration(response.ExpiresOn - DateTimeOffset.UtcNow - TimeSpan.FromSeconds(60));

    return response.Token;
}, static options => options
    .SetDuration(TimeSpan.FromSeconds(30))
    .SetSkipDistributedCache(skip: true, skipBackplaneNotifications: true)
);
jodydonetti commented 1 month ago

Hi @onionhammer , yes I called it Adaptive Caching, and you can change most of the entry options inside the factory to adapt them to the factory result.

While we're here a tangential feature you may be interested in is Conditional Refresh.

Hope this helps!

onionhammer commented 1 month ago

Thank you! I love the thorough documentation, I should really dedicate some time to it ha

jodydonetti commented 1 month ago

Thanks, I really appreciate it 😊