Skip to content

Releases: ZiggyCreatures/FusionCache

v0.21.0-preview2

21 May 12:21
Compare
Choose a tag to compare
v0.21.0-preview2 Pre-release
Pre-release

⚠ PRE-RELEASE

This is a pre-release of FusionCache, so please be aware that although it contains some shiny new stuff (see below), it is also subject to change before the final release.

Having said that, you should also know that this version is already very polished, the api design surface area well modeled, performance-tuned, with full xml-docs and it has all the bells and whistles of a normal release.

🔂 Conditional Refresh

FusionCache now fully supports conditional refresh, which is conceptually similar to conditional requests in HTTP.

Basically it is a way to cache and re-use either an ETag, a LastModified date or both, so that it is possible to save resources by not fully getting a remote resource (think: a remote http service response) in case it was not changed since the last time we got it.

Thanks to the community member @aKzenT for the invaluable help with the design discussion.

See here for the issue.

🦅 Eager Refresh

It is now possible to tell FusionCache to eagerly start refreshing a value in the cache even before it's expired, all automatically and in the background (without blocking).

For example we can tell FusionCache to cache something for 10 min but eagerly start refreshing it after 90% of that (9 min) in the background, as soon as a GetOrSet(...) call is made after the specified threshold: in this way the fresh data will be ready earlier, and without having to wait for the refresh to complete when it would've expired.

Both eager refresh and the usual normal refresh + factory timeouts can be combined, without any problems.

See here for the issue.

📞 Added EagerRefresh event

A new event has been added, for when eager refresh actually occurs.

📜 Added WithoutLogger() builder method

With the introduction of the Builder in the v0.20.0 release, something was missing: a way to tell FusionCache to not use a logger, at all: now this is fixed.

Thanks to community member @sherman89 for pointing that out.

See here for the issue.

v0.21.0-preview1

01 May 16:38
Compare
Choose a tag to compare
v0.21.0-preview1 Pre-release
Pre-release

⚠ PRE-RELEASE

This is a pre-release of FusionCache, so please be aware that although it contains some shiny new stuff (see below), it is also subject to change before the final release.

Having said that, you should also know that this version is already very polished, the api design surface area well modeled, performance-tuned, with full xml-docs and it has all the bells and whistles of a normal release.

🔂 Conditional Refresh

FusionCache now fully supports conditional refresh, which is conceptually similar to conditional requests in HTTP.

Basically it is a way to cache and re-use either an ETag, a LastModified date or both, so that it is possible to save resources by not fully getting a remote resource (think: a remote http service response) in case it was not changed since the last time we got it.

Thanks to the community member @aKzenT for the invaluable help with the design discussion.

See here for the issue.

🦅 Eager Refresh

It is now possible to tell FusionCache to eagerly start refreshing a value in the cache even before it is expired.

For example we can tell FusionCache to cache something for 10min but eagerly start refreshing it after 9min in the background, so that it will be ready earlier without waiting for the refresh to end.

Although it's basically the same as caching something directly for 9min + enabling fail-safe + setting a very low factory soft timeout like 10ms, some community members requested it because it felt more intuitive this way, while others felt the other way around: therefore the addition, to support both approaches and be more welcoming.

Also, both approaches can be combined without problems.

See here for the issue.

📜 Added WithoutLogger() builder method

With the introduction of the Builder in the v0.20.0 release, something was missing: a way to tell FusionCache to not use a logger, at all: now this is fixed.

Thanks to community member @sherman89 for pointing that out.

See here for the issue.

v0.20.0

08 Apr 17:52
Compare
Choose a tag to compare

ℹ Update Notes

If you are updating from a previous version, please read here.

👷‍♂️ Added Builder support (docs)

There's now a really easy to use and flexible fluent API that supports the builder pattern.
This allows a nice modular setup of FusionCache when using dependency injection, with the ability to add components and configure them with a couple of keystrokes, like:

services.AddFusionCache()
  .WithSerializer(
    new FusionCacheSystemTextJsonSerializer()
  )
  .WithDistributedCache(
    new RedisCache(new RedisCacheOptions()
    {
      Configuration = "..."
    })
  )
  .WithBackplane(
    new RedisBackplane(new RedisBackplaneOptions()
    {
      Configuration = "..."
    })
  )
;

Thanks to the community member @aKzenT for the invaluable help with the design discussion.

See here for the original issue.

📛 Added Named Caches support (docs)

FusionCache now natively support multiple named caches via dependency injection, thanks to the new IFusionCacheProvider interface/service.
This makes it easy to register and retrieve different caches, potentially with different underlying caching storage (but not necessarily) and different configurations.
This is even easier thanks to the aforementioned Builder Pattern support, like this:

// USERS CACHE
services.AddFusionCache("UsersCache")
  .WithDefaultEntryOptions(opt => opt
    .SetDuration(TimeSpan.FromSeconds(10))
  )
;

// PRODUCTS CACHE
services.AddFusionCache("ProductsCache")
  .WithDefaultEntryOptions(opt => opt
    .SetDuration(TimeSpan.FromSeconds(30))
    .SetFailSafe(true, TimeSpan.FromMinutes(10))
  )
;

Then you can depend on an IFusionCacheProvider service and easily ask to it for a certain cache with a GetCache("MyCache") call.
For example in an mvc controller you can go like this:

public class HomeController : Controller
{
  IFusionCache _usersCache;
  IFusionCache _productsCache;

  public HomeController(IFusionCacheProvider cacheProvider)
  {
    _productsCache = cacheProvider.GetCache("ProductsCache");
    _usersCache = cacheProvider.GetCache("UsersCache");
  }

  public IActionResult Product(int id)
  {
    _productsCache.GetOrDefault<Product>($"product:{id}");
    // ...
  }
}

And again, thanks to the community member @aKzenT for the invaluable help with the design discussion here, too.

See here for the original issue.

🆕 Added CacheKeyPrefix option (docs)

Since there's now native support for multiple named caches, I'm currently playing with the idea of adding support for a CacheKeyPrefix option, that would be added in front of any cache key you specify with a certain FusionCache instance. This can be helpful to avoid cache key collisions when working with multiple named caches all sharing the same underlying caching storage mechanism (eg: memory, Redis, MongoDB, etc).

♾ Handle Infinity

There's now native support for infinite expirations, with specific optimizations in the code to avoid exceptions and for better perf.

See here for more.

📜 Custom Plugins Log Levels (docs)

Two new options have been added to control the level for plugins info/error log entries.

See here for more.

v0.20.0-preview2

29 Mar 22:22
134051f
Compare
Choose a tag to compare
v0.20.0-preview2 Pre-release
Pre-release

⚠ PRE-RELEASE

This is a pre-release of FusionCache, so please be aware that although it contains some shiny new stuff (see below), it is also subject to change before the final release.

Having said that, you should also know that this version is already very polished, the api design surface area well modeled, performance-tuned, with full xml-docs and it has all the bells and whistles of a normal release.

ℹ NOTE: if you are updating from a previous version, please read here.

Ok, enough with the warnings: let's talk about the features 🎉

👷‍♂️ Added Builder Pattern support

There's now a really easy to use and flexible fluent API that supports the builder pattern.
This allows a nice modular setup of FusionCache when using dependency injection, with the ability to add components and configure them with a couple of keystrokes, like:

services.AddFusionCache()
  .WithSerializer(
    new FusionCacheSystemTextJsonSerializer()
  )
  .WithDistributedCache(
    new RedisCache(new RedisCacheOptions()
    {
      Configuration = "..."
    })
  )
  .WithBackplane(
    new RedisBackplane(new RedisBackplaneOptions()
    {
      Configuration = "..."
    })
  )
;

NOTE: The api surface has changed a little bit from v0.20.0-preview1.

Thanks to the community member @aKzenT for the invaluable help with the design discussion.

See here for the issue.
See here for the docs.

📛 Added Named Caches support

FusionCache now natively support multiple named caches via dependency injection, thanks to the new IFusionCacheProvider interface/service.
This makes it easy to register and retrieve different caches, potentially with different underlying caching storage (but not necessarily) and different configurations.
This is even easier thanks to the aforementioned Builder Pattern support, like this:

// USERS CACHE
services.AddFusionCache("UsersCache")
  .WithDefaultEntryOptions(opt => opt
    .SetDuration(TimeSpan.FromSeconds(10))
  )
;

// PRODUCTS CACHE
services.AddFusionCache("ProductsCache")
  .WithDefaultEntryOptions(opt => opt
    .SetDuration(TimeSpan.FromSeconds(30))
    .SetFailSafe(true, TimeSpan.FromMinutes(10))
  )
;

Then you can depend on an IFusionCacheProvider service and easily ask to it for a certain cache with a GetCache("MyCache") call.
For example in an mvc controller you can go like this:

public class HomeController : Controller
{
  IFusionCache _usersCache;
  IFusionCache _productsCache;

  public HomeController(IFusionCacheProvider cacheProvider)
  {
    _productsCache = cacheProvider.GetCache("ProductsCache");
    _usersCache = cacheProvider.GetCache("UsersCache");
  }

  public IActionResult Product(int id)
  {
    _productsCache.GetOrDefault<Product>($"product:{id}");
    // ...
  }
}

And again, thanks to the community member @aKzenT for the invaluable help with the design discussion here, too.

See here for the issue.
See here for the docs.

🆕 Added CacheKeyPrefix option

Since there's now native support for multiple named caches, I'm currently playing with the idea of adding support for a CacheKeyPrefix option, that would be added in front of any cache key you specify with a certain FusionCache instance. This can be helpful to avoid cache key collisions when working with multiple named caches all sharing the same underlying caching storage mechanism (eg: memory, Redis, MongoDB, etc).

♾ Handle Infinity

There's now native support for infinite expirations, with specific optimizations in the code to avoid exceptions and for better perf.

See here for more.

📜 Custom Plugins Log Levels

Two new options have been added to control the level for plugins info/error log entries.

See here for more.

v0.20.0-preview1

03 Mar 22:12
Compare
Choose a tag to compare
v0.20.0-preview1 Pre-release
Pre-release

⚠ PRE-RELEASE

This is a pre-release of FusionCache, so please be aware that although it contains some shiny new stuff (see below), it is also subject to change before the final release.

Having said that, you should also know that this version is already very polished, the api design surface area well modeled, performance-tuned, with full xml-docs and it has all the bells and whistles of a normal release.

Ok, enough with the warnings: let's talk about the features 🎉

👷‍♂️ Added Builder Pattern support

There's now a really easy to use and flexible fluent API that supports the builder pattern.
This allows a nice modular setup of FusionCache when using dependency injection, with the ability to add components and configure them with a couple of keystrokes, like:

services.AddFusionCache(b => b
  .WithSerializer(
    new FusionCacheSystemTextJsonSerializer()
  )
  .WithDistributedCache(
    new RedisCache(new RedisCacheOptions()
    {
      Configuration = "..."
    })
  )
  .WithBackplane(
    new RedisBackplane(new RedisBackplaneOptions()
    {
      Configuration = "..."
    })
  )
);

Thanks to the community member @aKzenT for the invaluable help with the design discussion.

See here for more.

📛 Added Named Caches support

FusionCache now natively support multiple named caches via dependency injection, thanks to the new IFusionCacheProvider interface/service.
This makes it easy to register and retrieve different caches, potentially with different underlying caching storage (but not necessarily) and different configurations.
This is even easier thanks to the aforementioned Builder Pattern support, like this:

// USERS CACHE
services.AddFusionCache("UsersCache", b => b
  .WithDefaultEntryOptions(opt => opt
    .SetDuration(TimeSpan.FromSeconds(10))
  )
);

// PRODUCTS CACHE
services.AddFusionCache("ProductsCache", b => b
  .WithDefaultEntryOptions(opt => opt
    .SetDuration(TimeSpan.FromSeconds(30))
    .SetFailSafe(true, TimeSpan.FromMinutes(10))
  )
);

Then you can depend on an IFusionCacheProvider service and easily ask to it for a certain cache with a GetCache("MyCache") call.
For example in an mvc controller you can go like this:

public class HomeController : Controller
{
  IFusionCache _usersCache;
  IFusionCache _productsCache;

  public HomeController(IFusionCacheProvider cacheProvider)
  {
    _productsCache = cacheProvider.GetCache("ProductsCache");
    _usersCache = cacheProvider.GetCache("UsersCache");
  }

  public IActionResult Product(int id)
  {
    _productsCache.GetOrDefault<Product>($"product:{id}");
    // ...
  }
}

And again, thanks to the community member @aKzenT for the invaluable help with the design discussion here, too.

See here for more.

🆕 Added CacheKeyPrefix option

Since there's now native support for multiple named caches, I'm currently playing with the idea of adding support for a CacheKeyPrefix option, that would be added in front of any cache key you specify with a certain FusionCache instance. This can be helpful to avoid cache key collisions when working with multiple named caches all sharing the same underlying caching storage mechanism (eg: memory, Redis, MongoDB, etc).

This decision is not final, and I'm interested in getting the opinions from the community.

v0.19.0

12 Feb 21:16
Compare
Choose a tag to compare

🆕 Added DistributedCacheFailSafeMaxDuration option (docs)

After a request by the community member @RMcD a new entry option has been added to be able to specify a fail-safe max duration specific for the distributed cache level.

See here for more.

⚠ Behaviour change with stale data

After talking with community member @fkuhnert , an old thought re-emerged: for readonly methods like TryGet[Async] and GetOrDefault[Async] no stale data throttling should occur. This means that, even with fail-safe enabled, if there's some usable stale data it will be returned, BUT not saved. This makes sense, as a TryGet or a GetOrDefault does not suggest a "save" operation (see: Principle of Least Astonishment).

This should not change any apparent behaviour from the outside: the only thing potentially noticeable is that, if you have a large number of TryGet/GetOrDefault calls done on stale data, you may see some more of them going to the distributed cache, that's all.

🆕 Added ServiceStack JSON support

A new serializer is now available in its own package, to support the ServiceStack JSON serializer.

Thanks @mythz for yout support!

⛔ Added entry options normalization

Thanks to the community member @suhrab for spotting an edge case that could have been already handled.

When a user enable fail-safe and specifies a FailSafeMaxDuration lower than the Duration, the situation can feel messy since the thing being asked is not really in line with how FusionCache operates.

To avoid this, a new normalization phase has been added, to make all the values coherent with the situation.
In case a normalization occurs, FusionCache will also log it with a (configurable) Warning level.

See here for more.

📞 Added FactorySuccess event (docs)

A new event has been added that will trigger when a non-background factory completes successfully, after a request from community member @bartlomiejgawel (thanks for the tip!).
For the background one, keep using the BackgroundFactorySuccess event that already exists.

See here for more.

⚡ Performance Boost

When logging is enabled, FusionCache automatically generates a unique operation id per each operation (eg: each GetOrSet/GetOrDefault/TryGet/etc call) to make detective work easier while looking at the logs.

The generation of these operation ids now consumes 83% less cpu time and 45% less memory.

📕 Better docs

The docs has been expanded and refined: one of these changes is that in the Options now there's a clear indication about which entry options are compatible with adaptive caching, thanks to a chat with @celluj34.

Thanks Joe for the inspiration!

v0.18.0

18 Dec 21:19
Compare
Choose a tag to compare

🆕 Added SkipDistributedCache option

After some requests by the community, a new entry option has been added to skip the distributed cache only in specific calls, in a very granular way.

See here for more.

🆕 Added SkipDistributedCacheReadWhenStale option

It is now possible to skip distributed cache reads when the memory entry was stale: this will lead to a perf boost when the 2nd layer is not actually a distributed cache but just an out-of-process cache, like in mobile apps, standalone apps, games and more.

See here for more.

🐞 Better MemoryPack support for .NET 7

Thanks to an issue opened by @RMcD , it has been discovered that MemoryPack has a quite strange and non-standard way to handle transitive dependencies + code generation regarding .NET Standard 2.1 and .NET 7.
After having opened an issue on its repo + some back and forth with its author (thanks to @neuecc for your openness and support!), a solution has been found. The issue there remains, but at least now the integration between FusionCache and MemoryPack is good to go, even on .NET 7!

See here for more.

📢 Changed EnableBackplaneNotifications option to (inverted) SkipBackplaneNotifications

A small rename so that now everything is more aligned and intuitive.

See here for more.

📕 Better docs

Augmented some online docs and inline XML docs, for a better experience while coding.

v0.17.0

04 Dec 20:39
Compare
Choose a tag to compare

🆕 Added MemoryPack support

A new serializer is now available in its own package, to support the new MemoryPack serialization format.

It is based on the amazing work by @neuecc , and this new serializer seems to be already the fastest serializer in the .NET space.

Thanks for your hard work Yoshifumi!

↩️ Backplane auto-recovery now enabled by default

After a couple of releases where it was disabled by default, the initial response in real-world projects has been positive: therefore I decided to enable the auto-recovery feature by default for everyone 🎉

PS: of course you can always turn it off in case you are having problems.

v0.16.0

12 Nov 18:13
Compare
Choose a tag to compare

🆕 Added Protobuf support

A new serializer is now available in its own package, to support the Protobuf serialization format.

It is based on of the most used Protobuf serializers on .NET: protobuf-net (repo here) by @mgravell : thanks for your hard work!

🐞 Added some [DebuggerDisplay] usages

Some class have been decorated with the [DebuggerDisplay] attribute, for a better debugging experience.

💪 Better nullability annotations

Some methods and properties have been decorated even better with nullability annotations, so that static flow analysis can help us catch even more potential NREs (null reference exceptions).

🐵 Chaos may also mean typos

I never noticed that and, since it is only used internally, nobody really paid any attention to that but the community user @luizhtm was spot on in noticing a typo in the Fusio(n)CacheChaosUtils utility class: a missing "n"!

Now there's the correct one with the right name, but temporarily the old one also remains: the entire class and every method inside has been marked as [Obsolete] with an explanation of the issue and how to correct any reference.

Thanks again @luizhtm !

📕 Xml Docs

Added a couple more helpful descriptions.

v0.15.0

26 Oct 10:33
Compare
Choose a tag to compare

🆕 Added MessagePack support

A new serializer is now available in its own package, to support the MessagePack serialization format.

It is based on the most used one on .NET: MessagePack (repo here) by @neuecc : thanks for your hard work!

🆕 Added ReThrowSerializationExceptions

A new option has been added to better control de/serialization exceptions, and the internal flow has been made better around those potential exceptions.

NOTE: contrary to the already existing ReThrowDistributedCacheExceptions which is disabled by default, this option is enabled by default. The rationale is that, while an error while talking to the distributed cache may be transient (because the distributed cache is temporarily down, there's a network error, etc), de/serialization should either always work or not, and typically any error is because of an unsupported data type or a missing configuration, and that is something that we should know as soon as possible and not pretend like it can magically go away later with a retry (like, instead, a transient distributed cache error instead).

🐵 new ChaosSerializer

A new ChaosSerializer has been added (in the ZiggyCreatures.FusionCache.Chaos package) to better handle fail scenarios during de/serialization.

📕 Xml Docs

Fixed some typos and added a couple more helpful descriptions.