FusionCache

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

MIT License

Stars
1.6K
Committers
11

Bot releases are hidden (Show)

FusionCache - v0.18.0

Published by jodydonetti almost 2 years ago

๐Ÿ†• 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.

FusionCache - v0.17.0

Published by jodydonetti almost 2 years ago

๐Ÿ†• 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.

FusionCache - v0.16.0

Published by jodydonetti almost 2 years ago

๐Ÿ†• 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.

FusionCache - v0.15.0

Published by jodydonetti almost 2 years ago

๐Ÿ†• 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.

FusionCache - v0.14.0

Published by jodydonetti about 2 years ago

โ†ฉ๏ธ Backplane auto-recovery (experimental)

FusionCache now has a backplane auto-recovery feature!

It has been added to automatically recover from transient errors in the backplane by keeping a local queue of the notifications that have not been sent successfully. These notifications will be automatically retried as soon as the backplane will become available again, without having to do anything.

It also handles common edge cases, like out of order notifications, and it can also be limited in size to avoid too consuming too much memory, with a sensible heuristic about which notifications to keep.

๐Ÿงช NOTE: for now the feature is experimental, and must be manually enabled via the new EnableBackplaneAutoRecovery option.

More info here.

๐Ÿต Chaos-related split

The chaos-related utilities and components, like ChaosDistributedCache and ChaosBackplane, have been moved to a separate project (ZiggyCreatures.FusionCache.Chaos).

This should also slightly reduce dependencies and code size of the main package.

๐Ÿ“• Xml Docs

Added links to the related online documentation in the xml docs for most options, and fixed some typos.

๐Ÿ“• Docs

Added a page about Logging.

Added a chapter about the lock timeout option in the Cache Stampede page.

Added a chapter about notifications behaviour in the Backplane page.

Added a chapter about auto-recovery in the Backplane page.

โš  Removal of [Obsolete] members

Some members marked as [Obsolete] from a very very long time have been finally removed to clean up the code.

FusionCache - v0.13.0

Published by jodydonetti about 2 years ago

โณ Better inferred local expiration

A member of the community (@yzhoholiev , thanks!) noticed that the local (memory cache) expiration, when coming from the distributed cache, was not good enough: with this fix the inferred memory cache expiration in those situations is more precise.
In some scenario a little bit more memory may be used with the distributed cache (eg: when not using fail-safe, otherwise it stays the same) but that should not be very frequent and the additional memory should reasonably not be a problem.

See here for more.

FusionCache - v0.12.0

Published by jodydonetti over 2 years ago

๐Ÿ†• Added DistributedCacheDuration

Added a new entry option DistributedCacheDuration (as a nullable TimeSpan).
This serves as an optional specific duration for the distributed cache (if you are using one) to allow custom overrides of the "main" duration: in this way it is now possible for example to specify a duration in the memory cache of 1 min and a duration in the distributed cache of, say, 1 hour.
In theory this is useless if you are using a backplane but, in case you prefer not to or cannot for some reason, this would mitigate the synchronization problems you may encounter in a multi-node scenario.

See here for more.

๐Ÿ”— Added SourceLink support

FusionCache now supports SourceLink, which should make your debugging experience easier.

See here for more.

๐Ÿ›ก Added Deterministic Builds support

FusionCache now supports Deterministic Builds, which is a nice addition.

See here for more.

โš  Removal of a Duplicate() method override

The override removed has been marked [Obsolete] for a very very long time and hopefully nobody should've been using it.

FusionCache - v0.11.1

Published by jodydonetti over 2 years ago

โฑ Rollback of: use soft timeout if failSafeDefaultValue provided

A decision has been made to temporarily rollback a change made in v0.11.0.

To see why take a look at this comment.

The main reason is to avoid unwanted surprises for existing users, who could have suddenly started to receive sub-optimal values during a first call.

Discussion are ongoing on how to better handle this scenario.

FusionCache - v0.11.0

Published by jodydonetti over 2 years ago

This release includes a lot of small features, changes and fixes.

โ˜Ž๏ธ Better GetOrSet events

In a previous release there has been a small regression in the events emitted during a GetOrSet call: now it has been fixed.

See https://github.com/jodydonetti/ZiggyCreatures.FusionCache/issues/49

โฑ Use soft timeout if failSafeDefaultValue provided

Historically the soft timeout, if specified, has been used only when there was a fallback value in the form of an already expired cache entry.
Sadly, after having introduced the failSafeDefaultValue param, that has not been used to enable the soft timeout.
Now this is resolved thanks to @alexmaek , who also made their first contribution!

See https://github.com/jodydonetti/ZiggyCreatures.FusionCache/pull/67

Note
This feature has been rolled back in v0.11.1 release because it was not the right move. See the pull request above for more!

๐Ÿ’ฃ Optional re-throwing of distributed cache exceptions

Following a community request, it is now possible to enable re-throwing of distributed cache exceptions, if you feel like it.
This is done via the new ReThrowDistributedCacheExceptions option on the FusionCacheEntryOptions object.

See https://github.com/jodydonetti/ZiggyCreatures.FusionCache/issues/34

๐Ÿ“ข Better backplane timeouts handling

Now synthetic timeouts are handled in a more specific way, and there's a new BackplaneSyntheticTimeoutsLogLevel option in the FusionCacheEntryOptions object.

๐Ÿ“ข Better backplane error handling

The internal flow on backplane exceptions is now better, to let the (optional) circuit breaker do its job more easily.

๐ŸŽ‰ New Contributors

FusionCache - v0.10.0

Published by jodydonetti over 2 years ago

๐Ÿง™โ€โ™‚๏ธ Adaptive Caching (more)

FusionCache now supports adaptive caching!

This means having new GetOrSet overloads where it is possible to change some options inside the factory, to be able to adapt (hence the name of the feature) some of these options to the object being cached. A typical example is caching a fresh news article for a small Duration, and an old one for a higher one.

More examples and explanations in the related documentation.

๐Ÿš€ Better lock perf (in some scenarios)

There's a new optimization that kicks in automatically during a GetOrSet call if:

  • fail-safe is enabled (via IsFailSafeEnabled)
  • AND there's an expired entry available as a fallback
  • AND a FactorySoftTimeout has been specified
  • AND LockTimeout has NOT been specified (pretty common)

In this case it may happen that a during multiple concurrent GetOrSet calls for the same key, the first one acquired the lock and start executing the factory. During this time the other GetOrSet calls for the same cache key are put on hold (to prevent a cache stampede, see here). But if the factory takes too much time it doesn't make sense to wait for it for the other callers, if they allow fail-safe and there's stale data to use as a fallback.

So with this optimization this is exactly what happens, maybe granting a perf boost in thee situations.

NOTE: these early-returning GetOrSet calls btw will NOT temporarily re-save the stale data in the cache, because the currently running factory will do so nonetheless, and because doing so does not incur in extra factory calls, so we are still protected from the cache stampede problem.

๐Ÿ“ž More stale hit events

Thanks to a suggestion by @JoeShook , FusionCache now emit events for cache hit with isStale set to true not only when a fail-safe is being activated, but in all subsequent cache hits until the entry is replaced by a successful factory execution, which frankly makes more sense.

๐Ÿ†• Added HasDistributedCache

A new bool property has been added to IFusionCache to let you know if there is a distributed cache configured (like the already existing HasBackplane).

๐Ÿ“œ Logging (new warning in a specific case)

Added a warning log when setting up a backplane in this scenario:

  • a backplane is configured
  • AND a distributed cache is NOT configured
  • AND the option DefaultEntryOptions.EnableBackplaneNotifications is set to true

This is important to prevent shooting yourself in the foot without knowing it, and that may happen because without a distributed cache there is no shared state between nodes, and if by default the backplane notifications are enabled it means that every time something is put into the cache in a node, all the other nodes will wipe their copy, creating a never ending update-remove-update-remove-etc loop.

You can read more about a scenario like this in the backplane documentation.

FusionCache - v0.10.0-preview1

Published by jodydonetti over 2 years ago

๐Ÿง™โ€โ™‚๏ธ Adaptive Caching (more)

FusionCache now supports adaptive caching!

This means having new GetOrSet overloads where it is possible to change some options inside the factory, to be able to adapt (hence the name of the feature) some of these options to the object being cached. A typical example is caching a fresh news article for a small Duration, and an old one for a higher one.

More examples and explanations in the related documentation.

๐Ÿš€ Better lock perf (in some scenarios)

There's a new optimization that kicks in automatically during a GetOrSet call if:

  • fail-safe is enabled (via IsFailSafeEnabled)
  • AND there's an expired entry available as a fallback
  • AND a FactorySoftTimeout has been specified
  • AND LockTimeout has NOT been specified (pretty common)

In this case it may happen that a during multiple concurrent GetOrSet calls for the same key, the first one acquired the lock and start executing the factory. During this time the other GetOrSet calls for the same cache key are put on hold (to prevent a cache stampede, see here). But if the factory takes too much time it doesn't make sense to wait for it for the other callers, if they allow fail-safe and there's stale data to use as a fallback.

So with this optimization this is exactly what happens, maybe granting a perf boost in thee situations.

NOTE: these early-returning GetOrSet calls btw will NOT temporarily re-save the stale data in the cache, because the currently running factory will do so nonetheless, and because doing so does not incur in extra factory calls, so we are still protected from the cache stampede problem.

๐Ÿ†• Added HasDistributedCache

A new bool property has been added to IFusionCache to let you know if there is a distributed cache configured (like the already existing HasBackplane).

๐Ÿ“œ Logging (new warning in a specific case)

Added a warning log when setting up a backplane in this scenario:

  • a backplane is configured
  • AND a distributed cache is NOT configured
  • AND the option DefaultEntryOptions.EnableBackplaneNotifications is set to true

This is important to prevent shooting yourself in the foot without knowing it, and that may happen because without a distributed cache there is no shared state between nodes, and if by default the backplane notifications are enabled it means that every time something is put into the cache in a node, all the other nodes will wipe their copy, creating a never ending update-remove-update-remove-etc loop.

You can read more about a scenario like this in the backplane documentation.

๐Ÿ™ Tell me what you think

Please try it out and let me know so I can push the final version out.

FusionCache - v0.9.0

Published by jodydonetti over 2 years ago

๐Ÿ“ข Backplane (more)

FusionCache now has a fully functioning backplane, to ease synchronization between nodes in a multi-node scenario.

It's very easy to setup and requires no additional work: it just works.

There are currently 2 implementations: one memory-only (mainly for testing) and one for Redis.

The backplane, like the 2nd level cache, is fully featured including events and logging and, since it talks to a separate system (eg: a Redis or Memcached instance), it natively support a simple circuit-breaker to better handle transient errors, again like the 2nd level cache.

๐Ÿ“• Better docs

Since the v0.9.0 is a big release with a great new feature, I took the chance and tried to improve the docs.

Of course there's the new part about the backplane and how to use it in various situations (both with and without the distributed cache).

I also collected all the IDistributedCache implementations available on Nuget, which is something I hope can be useful to the community as they can serve as the secondary cache layer.

Finally some typos have been corrected and a lot of small parts in general have been added where I felt they were missing.

๐Ÿ“œ Logging (fail-safe activation)

Thanks to a tip by the community (see here https://github.com/jodydonetti/ZiggyCreatures.FusionCache/issues/38), I changed a log level used when no fallback entry was available for a fail-safe activation, since it seemed more correct this way.

โš  Removed CacheKeyPrefix option

The FusionCacheOptions.CacheKeyPrefix option is now fully obsolete: it has been marked with the [Obsolete] attribute including the additional error flag, and is hidden via the [EditorBrowsable] attribute so its use will not compile anymore (see #33 for more).

โš  Removed Evict method

The Evict method was just something theoretically used to create the backplane, nothing to be used in the normal FusionCache usage.
Since in the end the final backplane design did not need this method, it has been removed to keep a more streamlined API.

FusionCache - v0.1.10-beta3

Published by jodydonetti over 2 years ago

This is the third and last BETA release containing the new Backplane #11 ๐ŸŽ‰.

It contains everything that was already in alpha1, alpha2, beta1 and beta2 plus:

๐Ÿ‘Œ Final polishing

In general this is the final polishing pass of everything.

๐Ÿ“• Better docs

The new docs are finished, particularly the ones about the new backplane and how to use it in various situations (both with and without the distributed cache). I also collected all the IDistributedCache implementations available on Nuget, which is something I hope can be useful to the community as they can serve as the secondary cache layer. Finally some typos have been corrected and more parts in general have been added where I felt they were missing.

๐Ÿ†• Removed Publish[Async] method

The tentative new Publish[Async] method was experimentally introduced a little while ago: it served its purpose, and since it was just an experiment and realliy only used internally, I decided to remove it before the next official version, so to keep a clean a slim api.

๐Ÿ†• Removed Evict method

The tentative new Evict method was experimentally introduced a little while ago: it served its purpose, and since it was just an experiment and realliy only used internally, I decided to remove it before the next official version, so to keep a clean a slim api.

๐Ÿ™ Tell me what you think

Please try it and let me know so I can push the final version out!

FusionCache - v0.1.10-beta2

Published by jodydonetti over 2 years ago

This is the second BETA release containing the new Backplane #11 ๐ŸŽ‰.

It contains everything that was already in alpha1, alpha2 and beta1 plus:

๐Ÿคฆโ€โ™‚๏ธ I'm as dumb as a rock

Because of some local code explorations + git reverts, I haven't in fact pushed the code for the backplane auto-setup in DI: this means that in a DI scenario we were not, in fact, using the backplane, even if properly configured.
Yep, I'm that dumb ๐Ÿ˜‘

โšก backplane subscription

Better initial backplane subscription handling, with a design that is more open for future extensibility.

๐Ÿ™ Tell me what you think

Please try it and let me know so I can push the final version out!

FusionCache - v0.1.10-beta1

Published by jodydonetti over 2 years ago

This is the first BETA release containing the new Backplane #11 ๐ŸŽ‰.

It contains everything that was already in alpha1 and alpha2 plus:

โš  A little refactoring

In preparation for the big official release I've changed a couple of names to make them prettier and shorter. For example I went from SendBackplaneNotification to Publish, etc

๐Ÿ“ข Backplane granularity

Now backplane notifications are more granular, differentiating between entry SET and REMOVE. Also added the instant in which a notification has been generated, for a better synchronization.

โšก Performance

Way better peformance for serialization of backplane messages (RedisBackplane).

๐Ÿ“œ Logging (backplane)

Added backplane options to the log string for FusionCacheEntryOptions.

๐Ÿ†• Added HasBackplane

A new bool property has been added to IFusionCache to let you know if there is a backplane.

๐Ÿ™ Tell me what you think

Please try it and let me know so I can push the final version out!

FusionCache - v0.1.10-alpha2

Published by jodydonetti over 2 years ago

This is the second alpha release containing the new Backplane #11 ๐ŸŽ‰.

It contains:

๐Ÿ“ž Events (backplane)

For both message sent/received.

๐Ÿ“œ Logging (backplane)

Added logging about the backplane.

๐Ÿ“œ Logging (fail-safe activation)

Also, thanks to a tip by the community (see here #38), I changed a log level used when no fallback entry was available for a fail-safe activation, since it seemed more correct this way.

๐Ÿ™ Tell me what you think

Please try it and let me know so I can push the final version out!


Of course, everything in the alpha1 is still included.

FusionCache - v0.1.10-alpha1

Published by jodydonetti over 2 years ago

Finally, this is the first (alpha) release containing the Backplane #11 ๐ŸŽ‰.

๐Ÿ“ข Backplane (alpha)

FusionCache finally has a fully functioning backplane: see here for more.

โš  Removed CacheKeyPrefix

The FusionCacheOptions.CacheKeyPrefix option is now fully obsolete: it has been marked with the [Obsolete] attribute including the additional error flag, so its use will not compile anymore (see #33 for more).

๐Ÿ™ Tell me what you think

Please try it and let me know so I can push the final version out!

FusionCache - v0.1.9

Published by jodydonetti almost 3 years ago

This is a small release, in preparation of the big one where the Backplane #11 will be added ๐ŸŽ‰.

๐Ÿ†• Added CacheName

It is now possible to specify a cache name, namely a logical name that identify a cache.

It can be used for identification, and in a multi-node scenario it is typically shared between nodes to create a logical association that may be useful to have them communicate together (ref Backplane).

It is possible to specify it in the FusionCacheOptions, and is acessible as a read-only prop directly on any FusionCache instance.

๐Ÿ†• Added InstanceId

Each time a new FusionCache instance is created (eg: via a new FusionCache(...) directly or via DI) a new id will be generated, globally and uniquely identifying that specific instance.

It can be useful to uniquely identify a single instance in a multi-node scenario, for example to precisely route notifications to each one (ref Backplane).

It is acessible as a read-only prop directly on any FusionCache instance.

๐Ÿ†• Added Evict method

A new Evict method has been added: this method evicts an entry from the cache, like the Remove method, but with 2 very important differencs:

  • it only act on the primary layer (memory cache) and does not propagate the removal in the distributed cache, if any
  • it does not raise a Remove event

Again, this is useful in the Backplane that is coming.

It is only available in a sync fashion and not in an async one, since it acts only locally and there's nothing to do asynchronously.

โš  Marked CacheKeyPrefix as [Obsolete] for future removal

The CacheKeyPrefix option is now obsolete: it still works, but will be kinda removed in the next version.

See here for more info.

๐Ÿš€ Performance

Added a couple of small perf optimizations here and there.

FusionCache - v0.1.7

Published by jodydonetti about 3 years ago

๐Ÿ”€ New option

A new FusionCacheOptions.DistributedCacheKeyModifierMode option has been added, so that you can now control how the cache key will be modified to be used in the distributed cache (Prefix, Suffix or None).
The default value is Prefix but, if for example you are having problems with Redis ACLs (which are prefix-based), you can change this to Suffix (or even None) to solve them.

๐Ÿ™ Thanks

Thanks to RogerSep for the hint about Redis ACLs, I hope this will solve your problem!

FusionCache - v0.1.6

Published by jodydonetti about 3 years ago

๐Ÿš€ Switch from Task<T> to ValueTask<T>

The async part of the api surface area has been migrated from using the Task<T> type to the ValueTask<T> type.
This allows saving a good amount of memory allocations, making our apps more performant.

Is this a breaking change? In short, no.
To expand on it a little bit more, it could be if you directly used a Task<T> returned from one of the async methods, instead of awaiting it normally. In that case simply add .AsTask() to turn the ValueTask<T> into a Task<T> and everything will be fine.

In all other normal usage scenarios, just awaiting on one of the async methods would work absolutely the same, while also allocating less memory ๐ŸŽ‰

โš ๏ธ Breaking changes

I've finally removed the TryGetResult<T> type, marked as [Obsolete] from a lot of time now.
It has been replaced a long ago with the MaybeValue<T> type, which is better designed and used also as an input, and not just an output.
For more information about the change please read the "Breaking change" section of the v0.1.3 release.
The same goes for the Success prop in the MaybeValue<T> type, also marked as [Obsolete] since the beginning and added just to allow a more pleasant transition from the old type to the new one.

๐Ÿ™ Thanks

Thanks to the the great Marc Gravell and Stephen Toub for their writings on this subject, in particular this and this which helped clear my mind on the subject.