A. L
A. L

Reputation: 339

Execute callback when django.cache.set timeout is exceeded

I use Django cache with django-redis==5.0.0 like this:

cache.set(f'clean_me_up_{id}', timeout=10)

Storing an entry into cache, which will be cleared after timeout, works perfectly for me.

What I´m trying to acheive, is to execute also some cleanup code (as a callback?) when the cache is deleted.

Is there some easy way to do this as it would be extremely helpful.

Upvotes: 1

Views: 100

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477533

The cache is not controlled by Django: what Django does is ask redis to insert a key with that timeout. Redis thus manages the keys, and will decide to remove a key. Django also does not know when redis does that, so you can not hook a callback to it. Most of these key-value stores also don't proactively remove keys: they don't wait a certain time to then remove the key: essentially when they read a key they check if the key has timedout, and if so remove it. Or when they need to allocate more space, they first look if they can remove keys that have been expired to reduce space and thus prevent allocating more space. It gives the impression redis deletes at a certain time, but it does not set a timer to do so.

If you need this, you probably should make table of items to clean up, so essentially make a model Trigger that is then created, and periodically check which triggers should run, and remove these from the database. Indeed, you can work with a model:

from datetime import timedelta

from django.utils.timezone import now


class Trigger(models.Model):
    value = models.IntegerField()
    when = models.DateTimeField()

    @classmethod
    def add_trigger(cls, value, timeout):
        Trigger.objects.create(
            value=value, when=now() + timedelta(seconds=timeout)
        )

    @classmethod
    def check_triggers(cls, handler):
        items = Trigger.objects.filter(when__lte=now())
        Trigger.objects.filter(pk__in=[item.pk for item in items])
        for item in items:
            handler(item.value)

You thus can set a trigger with:

Trigger.add_trigger(my_id, 10)

and then periodically check if items have expired and run a handler with:

def my_handler(item):
    print(item)


Trigger.check_triggers(my_handler)

and for example schedule this in a cronjob.

Upvotes: 0

Related Questions