You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django Redis缓存键超时删除时执行回调清理代码?

如何在Django Redis缓存键超时删除时执行回调清理代码?

嗨,这个需求我之前也碰到过!默认情况下Redis的键超时删除是后台被动/定期处理的,不会主动通知Django触发回调,所以得靠一些额外手段来实现。结合你用的django-redis==5.0.0,给你几个实用的方案:

方案一:利用Redis键空间通知(Keyspace Notifications)

这是最贴合“键超时自动触发”需求的方案,Redis支持通过订阅特定频道来监听键的过期事件。

步骤1:开启Redis的键空间通知

首先得修改Redis配置(或者动态设置),让它发送过期事件通知:

  • 打开redis.conf,找到notify-keyspace-events配置项,改成notify-keyspace-events "Ex"(E表示键事件,x表示过期事件)
  • 或者在Redis命令行执行动态配置(重启后失效):
    redis-cli config set notify-keyspace-events Ex
    

步骤2:在Django中监听过期事件

你可以在Django里启动一个独立的线程(或者用守护进程)来订阅Redis的过期事件频道,处理特定键的清理逻辑。示例代码如下:

import redis
from django.conf import settings

def listen_for_expired_keys():
    # 用django-redis的配置连接Redis
    r = redis.Redis.from_url(settings.CACHES['default']['LOCATION'])
    # 订阅0号数据库的过期事件频道(如果你的缓存用了其他数据库,替换成对应数字)
    pubsub = r.pubsub()
    pubsub.subscribe('__keyevent@0__:expired')
    
    for message in pubsub.listen():
        # message['data']是字节类型,转成字符串
        key = message['data'].decode('utf-8')
        # 判断是不是我们要处理的键
        if key.startswith('clean_me_up_'):
            # 提取ID,执行你的清理代码
            item_id = key.split('_')[-1]
            print(f"执行清理逻辑,ID:{item_id}")
            # 这里替换成你的实际清理操作,比如删除关联资源、更新数据库等
            # cleanup_function(item_id)

# 可以在Django启动时启动这个监听线程,比如在apps.py的ready方法里
# 注意:生产环境建议用独立进程或者守护进程运行,避免Django重启时中断监听

优缺点

  • 优点:能精准监听Redis自动触发的键过期事件,和缓存过期逻辑强绑定
  • 缺点:需要修改Redis配置,过期事件可能有轻微延迟(Redis的定期删除策略导致),监听线程/进程需要稳定运行,否则会错过事件

方案二:用Celery定时任务模拟回调

如果你的项目已经在用Celery,这个方案会更简单——在设置缓存的同时,创建一个和缓存超时时间一致的定时任务,到点自动执行清理逻辑。

示例代码

首先定义Celery任务:

# tasks.py
from celery import shared_task
from django.core.cache import cache

@shared_task
def cleanup_task(item_id):
    # 可选:先检查缓存键是否已经被删除(避免手动删除缓存后任务仍执行)
    if not cache.get(f'clean_me_up_{item_id}'):
        # 执行你的清理代码
        print(f"执行清理逻辑,ID:{item_id}")
        # cleanup_function(item_id)

然后在设置缓存的地方同时调用定时任务:

from django.core.cache import cache
from .tasks import cleanup_task

# 设置缓存
cache.set(f'clean_me_up_{id}', 'some_value', timeout=10)
# 同时创建定时任务,10秒后执行
cleanup_task.apply_async(args=[id], countdown=10)

优缺点

  • 优点:不需要修改Redis配置,依赖Celery的话实现成本低,任务执行更可靠(Celery有重试机制)
  • 缺点:如果缓存被手动提前删除,定时任务还是会执行(不过可以加缓存存在性检查避免);如果缓存超时时间被修改,任务的countdown也要同步调整

方案三:自定义缓存后端(仅适用于主动删除场景)

如果你还需要处理**主动调用cache.delete()**时的回调,可以自定义一个缓存后端继承django-redis的RedisCache,重写delete方法:

# custom_cache.py
from django_redis.cache import RedisCache

class CustomRedisCache(RedisCache):
    def delete(self, key, version=None, client=None):
        # 先执行父类的删除逻辑
        result = super().delete(key, version, client)
        # 判断是不是目标键,执行清理代码
        if key.startswith('clean_me_up_'):
            item_id = key.split('_')[-1]
            # cleanup_function(item_id)
        return result

然后在settings.py里配置使用这个自定义后端:

CACHES = {
    'default': {
        'BACKEND': 'yourapp.custom_cache.CustomRedisCache',
        'LOCATION': 'redis://127.0.0.1:6379/1',
        # 其他django-redis配置...
    }
}

⚠️ 注意:这个方案无法处理Redis自动超时删除的情况,只能处理主动调用delete()的场景,所以如果你的需求是监听自动超时,这个方案只能作为补充。


备注:内容来源于stack exchange,提问作者A. L

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.16 11:20:31