信号重放防护:为Django信号添加幂等性与去重机制
防止因重试、重复提交或异步队列消费导致的信号多次执行。本教程引入基于请求指纹和Redis锁的信号去重装饰器,确保同一信号(如支付回调)只触发一次副作用。 · 难度:入门 · +10XP
信号重放防护
Django信号在分布式环境下可能被多次发送。我们将创建一个@idempotent_signal装饰器,为每个信号实例生成唯一指纹(基于发送者、参数和timestamp),利用Redis的SETNX实现分布式锁。如果信号在过期时间内再次触发,将被静默忽略。同时支持自定义TTL和重试策略。
from django.dispatch import Signal
import hashlib, time
from redis import Redis
redis_client = Redis()
def idempotent_signal(signal, ttl=300):
def decorator(receiver):
def wrapper(sender, **kwargs):
key = f'idempotent:{signal}:{hashlib.md5(str(kwargs).encode()).hexdigest()}'
if redis_client.setnx(key, 1):
redis_client.expire(key, ttl)
return receiver(sender, **kwargs)
return wrapper
return decorator