python - 可能的 django 竞争条件
问题描述
@receiver(post_save, sender=MyRequestLog)
def steptwo_launcher(sender, instance, **kwargs):
GeneralLogging(calledBy='MyRequestLog', logmsg='enter steptwo_launcher').save() # remember to remove this line
if instance.stepCode == 100:
GeneralLogging(calledBy='MyRequestLog', logmsg='step code 100 found. launch next step').save()
nextStep.delay(instance.requestId,False)
我想我只是目睹了我的代码失去了竞争条件。我的应用程序的后端会更新任务一的状态,并在应该启动下一个任务时将 stepCode 100 写入日志。应用程序的前端轮询以将当前步骤报告给最终用户。
似乎在后端创建了一个带有 stepCode 100 的条目后,前端请求很快就进来了,以至于 if instance.stepCode == 100: 从未被发现为 True。GeneralLogging 仅在可疑碰撞时报告一个条目,不会启动下一步。
我的问题是 1)确认这是可能的,我已经怀疑了。和 2) 一种解决此问题的方法,因此 nextStep 不会由于竞争条件而被跳过。
解决方案
这个问题缺少一堆可能有用的信息(例如缺少代码,缺少输出),但是任何形式的代码
if state == x:
change_state
当多个控制路径命中此代码时,有潜在的竞争条件。
处理此问题的两种最常见的方法是 (1) 锁:
with some_lock:
if state:
change_state
即在我们完成之前阻止其他人点击此代码,并且(2)排队:
queue.push(item_to_be_processed)
# somewhere else
item_to_be_processed = queue.pop()
数据库中的队列/锁实现可以使用select_for_update
和使用额外的processed
字段,即让“编写器”进程保存模型processed = False
并让“读取器”进程执行:
from django.db import transaction
...
with transaction.atomic():
items = MyRequestLog.objects.select_for_update(skip_locked=True).filter(
stepCode=100,
processed=False
)
for item in items:
do_something_useful(item) # you might want to pull this outside of the atomic block if your application allows (so you don't keep rows locked for an extended period)
item.processed = True
item.save()
ps:检查您的数据库以获得支持(https://docs.djangoproject.com/en/2.0/ref/models/querysets/#select-for-update)
推荐阅读
- swift - 从存储在 SQLite 中的字符串重新转换时 UIImage 颠倒
- html - 如何在六边形的右侧添加彩色阴影?
- amazon-web-services - 主机的真实性......当我连接到实例时无法建立。AWS EC2
- reactjs - React useEffect hook,当依赖项是深度嵌套的对象时,是否存在依赖项
- linux - 使用find命令删除批处理文件中超过30天的文件时如何排除多个子目录(相同的目录名称)?
- mule - 如何将 JSON 数组展平为 csv 文件
- gradient-descent - allennlp.predictors.predictor.get_gradients 出错 RuntimeError: Expected object of backend CUDA but got backend CPU for argument #3 'index'
- r - 如何从数百个具有唯一标签的.csv目录生成大量数据集到列[R]?
- r - 如何分隔包含有序对列表的列?
- nginx - nginx 无法加载静态 .mp4