信号驱动的竞态条件防御模式
深入 Django 信号机制,揭示异步请求下信号处理器的竞态危害,并给出基于数据库锁与事务隔离的解决方案。 · 难度:入门 · +10XP
信号竞态条件防御
当 post_save 信号处理器中执行下游操作(如发送邮件、更新统计)时,并发请求可能导致重复执行或状态不一致。本教程将演示 select_for_update 与 transaction.atomic 结合信号的正确用法,并实现信号去重装饰器。你将学会使用 Redis 分布式锁防止信号重复触发,以及利用 F() 表达式避免统计字段竞争。
from django.db import transaction
from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import Order
@receiver(post_save, sender=Order)
def handle_order_save(sender, instance, **kwargs):
with transaction.atomic():
# 锁住相关行
locked = Order.objects.select_for_update().get(pk=instance.pk)
if not locked.processed:
# 执行一次性操作
locked.processed = True
locked.save(update_fields=['processed'])