Django中transaction.atomic是否覆盖其装饰函数内调用的Celery任务操作?
问题解答
核心结论
被@transaction.atomic装饰的create函数,完全不会覆盖或影响createUserTenant异步任务内的数据库操作,原因如下:
- Django的事务是和当前数据库连接绑定的,
@transaction.atomic的作用范围仅局限于当前Django请求线程内的数据库操作。你通过.delay()触发的Celery异步任务,运行在独立的Celery Worker进程/线程中,和当前请求完全隔离,既不会复用同一个数据库连接,也不受当前请求的事务控制。 - 你当前的代码存在隐性bug:
@transaction.atomic装饰的函数会等整个函数执行完成且没有抛出异常时才会提交事务,你在formSerializer.save()之后立刻触发异步任务,此时事务还未提交,Celery Worker执行时查询CustomUser.objects.get(pk=userid)大概率会找不到对应记录,直接报错返回False。 - 你原有代码中
if createUserTenant.delay(NewUserRecord.id, connection.schema_name):的判断逻辑是错误的:.delay()方法仅会将任务提交到Celery队列后立刻返回AsyncResult对象,不会等待任务执行完成,这个判断永远为真,完全获取不到任务内部返回的state值。如果需要感知异步任务的执行结果,需要额外做轮询或者配置回调逻辑,不能在请求接口中直接判断.delay()的返回值。
修复方案
可以使用Django提供的事务提交钩子transaction.on_commit,保证异步任务在事务成功提交、用户记录已经写入数据库后再触发,修改后的create函数代码如下:
@transaction.atomic def create(self, request): formSerializer = CustomUserSerializer(data = request.data) if formSerializer.is_valid(): NewUserRecord = formSerializer.save() # 事务成功提交后再触发异步任务 transaction.on_commit( lambda: createUserTenant.delay(NewUserRecord.id, connection.schema_name) ) return Response(TeamSerializer(Team.objects.all(), many=True).data, status = status.HTTP_201_CREATED) return Response(formSerializer.errors, status.HTTP_400_BAD_REQUEST)
内容的提问来源于stack exchange,提问作者user13729875
相关产品推荐
相关产品推荐

