【问题标题】:Django Loop Through Objects After Bulk .update()大容量 .update() 后 Django 循环遍历对象
【发布时间】:2022-10-13 14:43:36
【问题描述】:

此代码在 cron 上运行。所以我想立即更新对象的状态,这样如果第二个 cron 在当前 cron 完成之前启动,这些对象就不会再次被拾取(这最终将在我的应用程序中开始发生。)

    # Grab all pending emails.
    emails = delivery_que.objects.filter(status='PENDING')
    emails.update(status='SENDING')

    # Loop through the pending emails.
    for email in emails:

当前代码不起作用,因为在我 .update() 之后我似乎不再有权访问这些对象。

这是我实施的解决方法:

    # Grab all pending emails.
    emails = delivery_que.objects.filter(status='PENDING')
    emails.update(status='SENDING')
    emails = delivery_que.objects.filter(status='SENDING')

    # Loop through the pending emails.
    for email in emails:

我还缺少另一个更好的解决方案吗?我不想再次查询数据库来重新选择我应该已经可以从第一个查询中访问的对象。

【问题讨论】:

  • 在下面的循环中,您是否将状态更改为“已发送”并再次保存每个状态?

标签: python django


【解决方案1】:

这里的问题是您正在运行重叠的进程,并且在任何时候都不知道对方在做什么。

简单的解决方案:

  1. 作业开始时,检查锁定记录。如果存在,则退出作业。
  2. 添加锁定记录(到数据库中的模型,触摸文件等)。
  3. 处理作业。
  4. 删除锁定记录作为作业的最后一件事。

    稍微复杂一点的解决方案:

    1. 在作业开始时,将所有记录从PENDING 更新为该进程的唯一值(例如PROCESSING_<uuid>
    2. 为具有该唯一值的记录运行更新。

      您也可以通过向模型添加另一个字段来做到这一点,例如。 processing_id 并检查它是否为空以及具有正确的 PENDING 状态。

      可能是最复杂的解决方案:

      • 使进程具有幂等性...

      我的意思是,如果它在同一记录上运行两次并不重要。从您在上面发布的代码来看,这实际上是正确的,因为您所做的只是将状态更改为SENDING,但我想您没有显示代码并且用户会收到双重电子邮件。

      如果您有确保不发送重复邮件的代码,这将不是问题 - 对象可能会被处理两次,但它只会在第一次发送电子邮件。

      在一个理想的世界里,像这样的所有进程无论如何都应该是幂等的,只是为了确保你永远不会遇到任何问题,如果有人设法在他们不应该运行它的情况下运行它。

【讨论】:

    猜你喜欢
    • 2020-06-09
    • 2020-11-08
    • 1970-01-01
    • 2020-04-30
    • 2017-06-12
    • 2015-10-31
    • 2014-11-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多