Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow expiration_time to be a callable #20

Closed
sqlalchemy-bot opened this issue Feb 6, 2013 · 6 comments
Closed

Allow expiration_time to be a callable #20

sqlalchemy-bot opened this issue Feb 6, 2013 · 6 comments
Labels

Comments

@sqlalchemy-bot
Copy link

Migrated issue, originally created by David Beitey (davidjb)

My current use-case is to cache a set of values for a relative amount of time -- in one case, until the end of the current day, in another, until the end of the given week, and finally, until a certain date/time.

Currently, dogpile.cache accepts an expiration_time as an integer, which represents a fixed number seconds from now (eg in 24 hours time), and not a relative or otherwise dynamic value. In order to obtain a relative expiration_time for use, you could use get_or_create directly and calculate the necessary value when run, but for the cache_on_arguments decorator, this isn't possible given its nature as a decorator.

So, my suggestion is to allow expiration_time to be specified as callable that returns a integer and call this whenever expiration_time is used (eg in the CacheRegion.get and get_or_create functions). Thus, the expiration time is dynamic and since a function, the resulting relative time could be based upon anything (not just relative times as I mention above).

For example:

#!python
 
class CacheRegion(object):
    ...
    def get_or_create(self, key, creator, expiration_time=None):
        if hasattr(expiration_time, '__call__'):
            expiration_time = expiration_time()
        ...

def seconds_til_tomorrow():
    #or something else like a database call or whatever
    tomorrow = date.today() + timedelta(days=1)
    til_tomorrow = datetime.combine(tomorrow, time(0)) - datetime.now()
    return math.ceil(til_tomorrow.total_seconds())


region = make_region().configure('memory', expiration_time=seconds_til_tomorrow)
config.rest_of_day.get_or_create('1', lambda: datetime.date.today()) #Caches value of today's date til tomorrow
@sqlalchemy-bot
Copy link
Author

Michael Bayer (zzzeek) wrote:

fair enough, though do you think the callable is really only needed by cache_on_arguments()? at least that way we could avoid invoking callable(invalidation_time) for every cache get.

@sqlalchemy-bot
Copy link
Author

David Beitey (davidjb) wrote:

If you set a callable expiration_time, and it is resolved in cache_on_arguments, then the value is relative to when the decorator was applied/executed (eg application startup), rather than relative to when the caching happens. So, this means that the callable would need to be run within the decorated function itself -- to run whenever this decorated function is called so the expiration time can be dynamic (relative). My thinking is that this could be just before the call to get_or_create (line 577 of region.py).

It does present potential for performance issues, but it would be on the user not to do something overly complicated in the callable. However, the expires callable could itself be cached by the user, too.

Any other suggestions otherwise?

@sqlalchemy-bot
Copy link
Author

Michael Bayer (zzzeek) wrote:

If you set a callable expiration_time, and it is resolved in cache_on_arguments, then the value is relative to when the decorator was applied/executed (eg application startup), rather than relative to when the caching happens.

I'm not suggesting that the function be called immediately within the cache_on_arguments decorator, just that we'd determine at app startup if the argument is a callable or not:

#!python

# inside the decorator, at app startup time
is_callable = callable(argument)

# ...

# inside the decorator when we're about to call get_or_create
if is_callable:
    timeout = argument()
else:
   timeout = argument

My thinking is that this could be just before the call to get_or_create (line 577 of region.py).

yes, this is where we'd actually call the callable.

It does present potential for performance issues, but it would be on the user not to do something overly complicated in the callable.

well only if a callable is presented. I'm just trying to avoid latency for the vast majority of use cases that only send a scalar value here.

@sqlalchemy-bot
Copy link
Author

David Beitey (davidjb) wrote:

See pull request #19.

@sqlalchemy-bot
Copy link
Author

Michael Bayer (zzzeek) wrote:

7555c6a 8c0998f

@sqlalchemy-bot
Copy link
Author

Changes by Michael Bayer (zzzeek):

  • changed status to closed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant