Closed jvmlet closed 2 weeks ago
Just noticed the latest Fail-Safe Without Exceptions
feature .... so I suggest the same functionality only with syntax sugar by returning MaybeValue.NONE
from factory function.
BTW, which value returns GetOrSet
if ctx.Fail(message)
was called ? default
/null
?
Problem
Cache entry factory method might return
null
value
Yes, and NOT caching it is usually a mistake.
The usual example is what happens if you have a website with a url like /product/{id}
and I keep calling the url /product/999999
? That is an self-inflicted DoS, beause for every single call you'll go to the database, get back nothing and don't cache it, rinse and repeat.
What you can do instead is simply use GetOrSet()
with adaptive caching and, in case of null
, you set the Duration
to something lower than normal, like:
1 min
1 sec
or something like that.
This would still protect you from Cache Stampede and similar problem, while wllowing you to cache null
s for a very short amount of time.
it's easier to just have shortcut like this
MaybeValue<Something> v = _cache.TryGetWithTrySet(key, ()=> return MaybeValue of Something)
rather than
var smthng= _cache.TryGet<Something>(key); if (!smthng.HasValue) { something= // try fetch it if(something.HasValue){ _cache.Set(key, something.Value); } }
This code has a couple of problems:
1) by using a GET and SET separate calls (TryGet()
+ Set()
), you are not protected from Cache Stampede (without using GetOrSet()
it's impossible to coordinate the 2 calls)
2) as said in the first part of the answer, if you only call Set()
when the fetch is successful, 10 consecutive (or even parallel) calls will all go the the database, probably overloading it
Hope this helps!
BTW, which value returns
GetOrSet
ifctx.Fail(message)
was called ?default
/null
?
If fail-safe is enabled AND there's a stale value to use, the stale value will be returned (that's the whole point of fail-safe).
If instead fail-safe is not enabled or there's no stale value to use, an exception will be thrown (with the specified message).
I'm exploring a future TryGetOrSet()
method that is basically a TryGet()
+ GetOrSet()
combination, and that would return a MaybeValue<T>
when there's a problem, but it's not ready yet.
Hope this helps.
Hi @jvmlet , any thoughts on this?
Too much if... then
, IMO.
Public API has to be easy to understand and leave no place for ambiguity.
I think that retuning Maybe
from setter is more friendly than setting flag on context+configuring other flags that define the behavior.
User can then use adaptive cache feature to define whether or not to cache empty value returned from setter.
Too much
if... then
, IMO. Public API has to be easy to understand and leave no place for ambiguity.
Ok but, I mean... hybrid multi-level caching with resiliency features, soft-healing, and so on all in one package is a quite complex beast, and not everything can be reduced to an easy peasy yes/no.
Anyway, how would you design an unambiguous, easy to use public API for this (but, mind you, still support all the options and features available)? Maybe I can get some inspiration for some potential changes.
I think that retuning
Maybe
from setter is more friendly than setting flag on context+configuring other flags that define the behavior
I think you meant "factory" and not "setter", and in that case: if the factory is (simplifying) Func<T>
it cannot return a MaybeValue<T>
instead (that's the C# language). Also, how would you define all the other "flags" to tweak the behaviour then?
Anyway, let's play with your idea: returning MaybeValue would mean "don't cache it", right?
Now imagine the next user coming along and saying "Hey, I'm caching MaybeValue
s, and I noticed that if I return a MaybeValue.None
it's not getting cached, why is that?" and than we would need to explain that MaybeValue.None is a magic value that behave in a specific way, so whatever the factory returns will be cached but IF it is this special value then it will not be cached etc...
So they would say "Too much if... then
, IMO. Public API has to be easy to understand and leave no place for ambiguity." and we would be back at square one.
Also, by not caching it there's still the problem I mentioned above (self inflicted DoS), so we should instead cache it for a small amount of time, but how much? It should be specifiable, and that is why I choose to do it via adaptive caching.
What do you think?
Since we are here, would you mind letting me know about the other points I've made? I'd like to know your POV on them.
These:
Yes, and NOT caching it is usually a mistake. The usual example is what happens if you have a website with a url like /product/{id} and I keep calling the url /product/999999 ? That is an self-inflicted DoS, beause for every single call you'll go to the database, get back nothing and don't cache it, rinse and repeat.
Also this:
I'm exploring a future TryGetOrSet() method that is basically a TryGet() + GetOrSet() combination, and that would return a MaybeValue
when there's a problem, but it's not ready yet.
Would this be more in line with your expectations?
Problem
Cache entry factory method might return
null
value, it's easier to just have shortcut like thisrather than