You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
I would like my cached methods to never return expired values and block wait instead. #264
function for this key against the cache. When the dogpile
lock cannot be acquired, the method will block if no
previous value is available, until the lock is released and
a new value available. If a previous value
is available, that value is returned immediately without blocking.
So what I have is an expired value in the cache.
Thread 1 retrieves it, notices it's expired, starts creating a new value, and will return the new value.
Meanwhile; Thread 2 retrieves it, notices it's expired, notices thread 1 is busy creating and returns the old value.
But the old value is entirely useless for my case. It's expired for a reason. Is there a way to configure the cache region to never return expired values and just block/wait for creation instead. Just like a cache miss?
(simplified) Code to reproduce my issue:
importosimporttimefrommultiprocessingimportProcessfromdogpile.cacheimportmake_regioncache_region=make_region()
cache_region.configure(
"dogpile.cache.dbm",
expiration_time=1,
arguments={
"filename": "/tmp/cache.dbm",
},
)
@cache_region.cache_on_arguments()defget_value():
print(os.getpid(), "Making new value...")
time.sleep(2)
returnf"Got value {time.time():.0f}"defrun():
print(os.getpid(), get_value())
print("3 sync calls in a row (value should be made once):")
run()
run()
run()
processes= []
foriinrange(2):
process=Process(target=run)
processes.append(process)
time.sleep(2)
print()
print("2 async calls after cache expired (value should be made once) and be different from the previous:")
forprocessinprocesses:
process.start()
forprocessinprocesses:
process.join()
Example output:
3 sync calls in a row (value should be made once):
103954 Making new value...
103954 Got value 1740579012
103954 Got value 1740579012
103954 Got value 1740579012
2 async calls after cache expired (value should be made once) and be different from the previous:
103978 Got value 1740579012
103977 Making new value...
103977 Got value 1740579016
In the above output, the line 103978 Got value 1740579012 is bad for me. That should never return an expired value.
Meanwhile; Thread 2 retrieves it, notices it's expired, notices thread 1 is busy creating and returns the old value.
well that's the entire secret sauce of "dogpile cache" :)
There's a way out for this one though it's not as flexible as it should be, but you can add a region invalidation strategy that considers any timeout to be hard invalidated. can confirm this works with your clear test case, thanks for that
Thanks for your swift reply. (I changed my sample code to dbm in the meantime, thinking it would be easier to run in case you didnt run redis, but anyway doesn't matter)
I did indeed look at the InvalidationStrategy, but didn't see a decent way to get the expiration time. I did not think to just pass the region to a custom constructor there 🤦
Extra question with this solution though. Would there be a way to figure out the correct expiration time if it's overridden on the decorator?
IIRC, I've implemented this in the past with a custom ProxyBackend. Within the custom ProxyBackend, you can analyze the timestamp in the metadata payload and return NO_VALUE for expired timestamps. As far as dogpile.cache's logic is concerned, this is a cache miss. The expiry in the metadata should reflect the override.
Activity
zzzeek commentedon Feb 26, 2025
well that's the entire secret sauce of "dogpile cache" :)
There's a way out for this one though it's not as flexible as it should be, but you can add a region invalidation strategy that considers any timeout to be hard invalidated. can confirm this works with your clear test case, thanks for that
Wim-De-Clercq commentedon Feb 26, 2025
Thanks for your swift reply. (I changed my sample code to dbm in the meantime, thinking it would be easier to run in case you didnt run redis, but anyway doesn't matter)
I did indeed look at the InvalidationStrategy, but didn't see a decent way to get the expiration time. I did not think to just pass the region to a custom constructor there 🤦
Extra question with this solution though. Would there be a way to figure out the correct expiration time if it's overridden on the decorator?
zzzeek commentedon Feb 26, 2025
not at the moment hence not as flexible as it should be
jvanasco commentedon Sep 12, 2025
IIRC, I've implemented this in the past with a custom ProxyBackend. Within the custom ProxyBackend, you can analyze the timestamp in the metadata payload and return NO_VALUE for expired timestamps. As far as
dogpile.cache's logic is concerned, this is a cache miss. The expiry in the metadata should reflect the override.