如何在将模型字段更新为最新时间戳时避免竞争条件
How to avoid race condition in updating model field to newest timestamp
我需要跟踪最近一次在 post 中提及用户的时间,并在每次基于 post 创建新的 post 时更新此字段时间.
我当前的代码如下所示:
from django.db.models.signals import post_save
from django.dispatch import receiver
from messageboard.models import Post
@receiver(post_save, sender=Post)
def user_last_mentioned_updater(sender, instance, **kwargs):
for users in instance.mentions:
user.last_mentioned = max(user.last_mentioned, instance.timestamp)
user.save()
但是,如果同时处理两个 post,这可能会使 last_mentioned
字段保留在较早 post 的时间戳。
不幸的是,F
不支持 max
操作,当我尝试它时,我得到一个 TypeError: unorderable types: datetime.datetime() > F()
:
user.last_mentioned = max(F('last_mentioned'), instance.timestamp)
如何避免这种竞争情况?
如果重要的话,目前我将 Postgresql 用于 ORM,尽管这可能会发生变化。
这是一个应该没有竞争条件并且更高效的版本:
@receiver(post_save, sender=Post)
def user_last_mentioned_updater(sender, instance, **kwargs)
User.objects.filter(
id__in=[u.id for u in instance.mentions],
last_mentioned__lt=instance.timestamp,
).update(last_mentioned=instance.timestamp)
也就是说,我们 select 提到的用户的时间戳需要更新,并在单个 SQL 语句中更新它们。
我需要跟踪最近一次在 post 中提及用户的时间,并在每次基于 post 创建新的 post 时更新此字段时间.
我当前的代码如下所示:
from django.db.models.signals import post_save
from django.dispatch import receiver
from messageboard.models import Post
@receiver(post_save, sender=Post)
def user_last_mentioned_updater(sender, instance, **kwargs):
for users in instance.mentions:
user.last_mentioned = max(user.last_mentioned, instance.timestamp)
user.save()
但是,如果同时处理两个 post,这可能会使 last_mentioned
字段保留在较早 post 的时间戳。
不幸的是,F
不支持 max
操作,当我尝试它时,我得到一个 TypeError: unorderable types: datetime.datetime() > F()
:
user.last_mentioned = max(F('last_mentioned'), instance.timestamp)
如何避免这种竞争情况?
如果重要的话,目前我将 Postgresql 用于 ORM,尽管这可能会发生变化。
这是一个应该没有竞争条件并且更高效的版本:
@receiver(post_save, sender=Post)
def user_last_mentioned_updater(sender, instance, **kwargs)
User.objects.filter(
id__in=[u.id for u in instance.mentions],
last_mentioned__lt=instance.timestamp,
).update(last_mentioned=instance.timestamp)
也就是说,我们 select 提到的用户的时间戳需要更新,并在单个 SQL 语句中更新它们。