【问题标题】:run code after transaction commit in Django在 Django 中事务提交后运行代码
【发布时间】:2010-10-31 07:34:59
【问题描述】:

有什么方法可以在 Django 中事务提交后运行一些代码?

我需要将一些消息发送到rabbitmq服务器进行离线处理,但消息在Django事务提交之前到达消费者。

我的消息是在模型的 post_save 信号中发送的。我正在寻找的是一种类似的机制,使用信号或其他东西,它将在提交后执行代码(如果事务失败则不执行任何操作)。

我还没有在 Django 中找到任何通用的方法。你有什么想法吗?

【问题讨论】:

  • 我遇到了类似的问题。在 post_save 上,Publisher(进程 1)保存任务状态并发布消息。消费者(进程 2)接收消息并更新任务状态,该状态尚未在数据库中。有效的方法是让消费者在收到消息后睡一两秒钟。反正感觉很脏。

标签: django transactions signals commit


【解决方案1】:

一种可能性是对事务中间件进行子类化,以便它在提交时发送自定义信号。您的代码可以侦听该信号,而不是 post_save。

【讨论】:

  • 谢谢,我想我会使用一些中间件(我可能会添加另一个中间件,而不是子类事务中间件)。不过,我担心信号。它们是线程安全的吗?如果另一个线程抛出一个信号,当前线程可以捕捉到它吗?
  • 我仍然有中间件的问题:如果应用程序从管理命令运行,它不会执行我的回调。
  • 我不认为你的线程问题真的有意义。信号对线程没有任何特殊作用。在一个线程中发送的信号将仅调用同一线程中的接收器。但是,内置信号对象是模块全局的,因此在一个线程中为 post_save 注册的信号处理程序会在所有线程中注册。 (我认为您自己的代码中可能有信号对象不是全局的,没有仔细查看)。
【解决方案2】:

django-transaction-hooks为Django built into Django 1.9+:

from django.db import transaction

def do_something():
    pass  # send a mail, invalidate a cache, fire off a Celery task, etc.

transaction.on_commit(do_something)

【讨论】:

  • 我之前必须在我的应用程序的其他部分工作,但我会遵循这条路径。准备好后,我将向 django-developers 发送一封电子邮件,并在补丁中添加错误报告。
  • 如果django-transaction-hooks对django版本要求太高,可以使用django-db-signals
【解决方案3】:

我已经通过猴子修补 django 实现了事务信号(post_commitpost_rollback): http://gist.github.com/247844

【讨论】:

    【解决方案4】:

    查看django-celery-transactions 以获得解决方案。

    我最近完成了将底层信号代码代码拆分并重构为独立应用程序django-db-signals

    【讨论】:

      【解决方案5】:

      希望这可以帮助使用 Django 1.9 或更高版本的人。从 1.9 开始,on_commit 可用。

      所以基本上你会这样做:

      from django.db import transaction
      
      transaction.on_commit(
          lambda: send_msg_to_rabbitmqp(param1, param2, ...)
      )
      

      如果你想保留post_save,你仍然可以使用on_commit

      @receiver(pre_save, sender=MyModel)
      def my_handler(sender, instance, created, **kwargs):
          transaction.on_commit(
              lambda: send_msg_to_rabbitmqp(instance.id)
          )
      

      【讨论】:

      • 如果我希望每次交易都执行挂钩,我应该把这段代码放在哪里?
      • @styrofoamfly 在模型的save() 方法中是我放的地方。您还可以注册一个调用transaction.on_commitpost_save 信号,我认为它注册得足够早,可以为该保存事务调用。
      • 您能否详细说明为什么我们需要lambda 语法才能将参数传递给on_commit 可调用对象? functools.partial 可以做到这一点,以使我们在其他地方调用具有完整定义的函数而不是真正的内联 lambda 函数更加明显吗?
      • lambda 仅用于将 send_msg_to_rabbitmqp(instance.id) 转换为可调用
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-04-09
      • 2019-04-26
      • 2017-09-03
      • 1970-01-01
      • 2018-05-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多