Выполнение обратного вызова при превышении таймаута django.cache.set

Я использую Django cache с django-redis==5.0.0 следующим образом:

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

Сохранение записи в кэше, которая будет очищена после таймаута, отлично работает для меня.

Что я пытаюсь достичь, так это выполнить некоторый код очистки (в качестве обратного вызова?), когда кэш удаляется.

Есть ли какой-нибудь простой способ сделать это, так как это было бы очень полезно.

Кэш не контролируется Django: Django просит Redis вставить ключ с указанным таймаутом. Таким образом, Redis управляет ключами и принимает решение об их удалении. Django также не знает, когда Redis это делает, поэтому вы не можете подключить к нему обратный вызов. Большинство из этих хранилищ ключевых значений также не проактивно удаляют ключи: они не ждут определенного времени, чтобы затем удалить ключ: по сути, когда они читают ключ, они проверяют, не истек ли таймаут, и если да, то удаляют его. Или когда им нужно выделить больше места, они сначала смотрят, могут ли они удалить ключи, срок действия которых истек, чтобы уменьшить пространство и таким образом предотвратить выделение большего пространства. Создается впечатление, что redis удаляет ключи в определенное время, но он не устанавливает для этого таймер.

Если вам это нужно, то, вероятно, следует составить таблицу элементов для очистки, то есть, по сути, сделать модель Trigger, которая затем создается, и периодически проверяет, какие триггеры должны выполняться, и удаляет их из базы данных. Действительно, вы можете работать с моделью:

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)

Таким образом, вы можете установить триггер с помощью:

Trigger.add_trigger(my_id, 10)

и затем периодически проверять, не истек ли срок годности предметов, и запускать обработчик с:

def my_handler(item):
    print(item)


Trigger.check_triggers(my_handler)

и, например, запланировать это в cronjob.

Вернуться на верх