Home

Awesome

<div align="center">

FusionCache logo

FusionCache

</div> <div align="center">

License: MIT Nuget

</div>
🙋‍♂ī¸ Updating to v1.0.0 ? please read here.

FusionCache is an easy to use, fast and robust hybrid cache with advanced resiliency features.

It was born after years of dealing with all sorts of different types of caches: memory caching, distributed caching, http caching, CDNs, browser cache, offline cache, you name it. So I've tried to put together these experiences and came up with FusionCache.

<div style="text-align:center;">

FusionCache diagram

</div>

Being a hybrid cache means it can transparently work as either a normal memory cache (L1) or as a multi-level cache (L1+L2), where the distributed 2nd level (L2) can be any implementation of the standard IDistributedCache interface: this will get us better cold starts, better horizontal scalability, more resiliency and overall better performance.

FusionCache also includes an optional backplane for realtime sync between multiple nodes and advanced resiliency features like cache stampede protection, a fail-safe mechanism, soft/hard timeouts, eager refresh, full observability via logging and OpenTelemetry and much more.

🏆 Award

<div align="center">

Google Award

</div>

On August 2021, FusionCache received the Google Open Source Peer Bonus Award: here is the official blogpost.

📕 Getting Started

With đŸĻ„ A Gentle Introduction you'll get yourself comfortable with the overall concepts.

Want to start using it immediately? There's a ⭐ Quick Start for you.

Curious about what you can achieve from start to finish? There's a 👩‍đŸĢ Step By Step guide.

đŸ“ē Media

More into videos?

I've been lucky enough to be invited on some shows and podcasts here and there: you can find them in the Media section.

A good example is when the fine folks at On .NET invited me on the show to allow me to mumbling random caching stuff.

<div align="center">

On .NET Talk

</div>

✔ Features

These are the key features of FusionCache:

<details> <summary>Something more 😏 ?</summary> <br/>

Also, FusionCache has some nice additional features:

</details>

đŸ“Ļ Packages

Main packages:

Package NameVersionDownloads
ZiggyCreatures.FusionCache <br/> The core packageNuGetNuget
ZiggyCreatures.FusionCache.OpenTelemetry <br/> Adds native support for OpenTelemetry setupNuGetNuget
ZiggyCreatures.FusionCache.Chaos <br/> A package to add some controlled chaos, for testingNuGetNuget

Serializers:

Package NameVersionDownloads
ZiggyCreatures.FusionCache.Serialization.NewtonsoftJson <br/> A serializer, based on Newtonsoft Json.NETNuGetNuget
ZiggyCreatures.FusionCache.Serialization.SystemTextJson <br/> A serializer, based on the new System.Text.JsonNuGetNuget
ZiggyCreatures.FusionCache.Serialization.NeueccMessagePack <br/> A MessagePack serializer, based on the most used MessagePack serializer on .NETNuGetNuget
ZiggyCreatures.FusionCache.Serialization.ProtoBufNet <br/> A Protobuf serializer, based on one of the most used protobuf-net serializer on .NETNuGetNuget
ZiggyCreatures.FusionCache.Serialization.CysharpMemoryPack <br/> A serializer based on the uber fast new serializer by Neuecc, MemoryPackNuGetNuget
ZiggyCreatures.FusionCache.Serialization.ServiceStackJson <br/> A serializer based on the ServiceStack JSON serializerNuGetNuget

Backplanes:

Package NameVersionDownloads
ZiggyCreatures.FusionCache.Backplane.Memory <br/> An in-memory backplane (mainly for testing)NuGetNuget
ZiggyCreatures.FusionCache.Backplane.StackExchangeRedis <br/> A Redis backplane, based on StackExchange.RedisNuGetNuget

Third-party packages:

Package NameVersionDownloads
JoeShook.ZiggyCreatures.FusionCache.Metrics.CoreNuGetNuget
JoeShook.ZiggyCreatures.FusionCache.Metrics.EventCountersNuGetNuget
JoeShook.ZiggyCreatures.FusionCache.Metrics.AppMetricsNuGetNuget

⭐ Quick Start

FusionCache can be installed via the nuget UI (search for the ZiggyCreatures.FusionCache package) or via the nuget package manager console:

PM> Install-Package ZiggyCreatures.FusionCache

As an example, imagine having a method that retrieves a product from your database:

Product GetProductFromDb(int id) {
	// YOUR DATABASE CALL HERE
}

💡 This is using the sync programming model, but it would be equally valid with the newer async one for even better performance.

To start using FusionCache the first thing is create a cache instance:

var cache = new FusionCache(new FusionCacheOptions());

If instead you are using DI (Dependency Injection) use this:

services.AddFusionCache();

We can also specify some global options, like a default FusionCacheEntryOptions object to serve as a default for each call we'll make, with a duration of 2 minutes:

var cache = new FusionCache(new FusionCacheOptions() {
	DefaultEntryOptions = new FusionCacheEntryOptions {
		Duration = TimeSpan.FromMinutes(2)
	}
});

Or, using DI, like this:

services.AddFusionCache()
	.WithDefaultEntryOptions(new FusionCacheEntryOptions {
		Duration = TimeSpan.FromMinutes(2)
	})
;

Now, to get the product from the cache and, if not there, get it from the database in an optimized way and cache it for 30 sec (overriding the default 2 min we set above) simply do this:

var id = 42;

cache.GetOrSet<Product>(
	$"product:{id}",
	_ => GetProductFromDb(id),
	TimeSpan.FromSeconds(30)
);

That's it 🎉

<details> <summary>Want a little bit more 😏 ?</summary>

Now, imagine we want to do the same, but also:

To do all of that we simply have to change the last line (reformatted for better readability):

cache.GetOrSet<Product>(
	$"product:{id}",
	_ => GetProductFromDb(id),
	// THIS IS WHERE THE MAGIC HAPPENS
	options => options
		.SetDuration(TimeSpan.FromSeconds(30))
		.SetPriority(CacheItemPriority.High)
		.SetFailSafe(true, TimeSpan.FromHours(2))
		.SetFactoryTimeouts(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(2))
);

Basically, on top of specifying the cache key and the factory, instead of specifying just a duration as a TimeSpan we specify a FusionCacheEntryOptions object - which contains all the options needed to control the behavior of FusionCache during each operation - in the form of a lambda that automatically duplicates the default entry options defined before (to copy all our defaults) while giving us a chance to modify it as we like for this specific call.

Now let's say we really like these set of options (priority, fail-safe and factory timeouts) and we want them to be the overall defaults, while keeping the ability to change something on a per-call basis (like the duration).

To do that we simply move the customization of the entry options where we created the DefaultEntryOptions, by changing it to something like this (the same is true for the DI way):

var cache = new FusionCache(new FusionCacheOptions() {
	DefaultEntryOptions = new FusionCacheEntryOptions()
		.SetDuration(TimeSpan.FromMinutes(2))
		.SetPriority(CacheItemPriority.High)
		.SetFailSafe(true, TimeSpan.FromHours(2))
		.SetFactoryTimeouts(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(2))
});

Now these options will serve as the cache-wide default, usable in every method call as a "starting point".

Then, we just change our method call to simply this:

var id = 42;

cache.GetOrSet<Product>(
	$"product:{id}",
	_ => GetProductFromDb(id),
	options => options.SetDuration(TimeSpan.FromSeconds(30))
);

The DefaultEntryOptions we did set before will be duplicated and only the duration will be changed for this call.

</details>

👩‍đŸĢ Step By Step

If you are in for a ride you can read a complete step by step example of why a cache is useful, why FusionCache could be even more so, how to apply most of the options available and what results you can expect to obtain.

<div style="text-align:center;">

FusionCache diagram

</div>

đŸ–Ĩī¸ Simulator

Distributed systems are, in general, quite complex to understand.

When using FusionCache with the distributed cache, the backplane and auto-recovery the Simulator can help us seeing the whole picture.

FusionCache Simulator

🧰 Supported Platforms

FusionCache targets .NET Standard 2.0 so any compatible .NET implementation is fine: this means .NET Framework (the old one), .NET Core 2+ and .NET 5/6/7/8+ (the new ones), Mono 5.4+ and more (see here for a complete rundown).

NOTE: if you are running on .NET Framework 4.6.1 and want to use .NET Standard packages Microsoft suggests to upgrade to .NET Framework 4.7.2 or higher (see the .NET Standard Documentation) to avoid some known dependency issues.

🆎 Comparison

There are various alternatives out there with different features, different performance characteristics (cpu/memory) and in general a different set of pros/cons.

A feature comparison between existing .NET caching solutions may help you choose which one to use.

💰 Support

Nothing to do here.

After years of using a lot of open source stuff for free, this is just me trying to give something back to the community.

If you really want to talk about money, please consider making ❤ a donation to a good cause of your choosing, and let me know about that.

đŸ’ŧ Is it Production Ready :tm: ?

Yes!

FusionCache is being used in production on real world projects for years, happily handling millions and millions of requests.

Considering that the FusionCache packages have been downloaded more than 6 million times (thanks everybody!) it may very well be used even more.

Oh, and it is being used in products by Microsoft itself, like Data API Builder!

😍 Are you using it?

If you find FusionCache useful please let me know, I'm really interested!

This is the only way for me to know how it is helping people.