Celery任务数据库数据过时:刚创建的BankEntry无法获取
问题根源:数据库事务未提交导致Celery任务读取不到数据
你遇到的这个问题其实是Django事务机制和Celery异步任务执行时机的冲突导致的,我来给你拆解清楚:
Django默认开启了自动事务管理,在视图函数中,整个请求的数据库操作会被包裹在一个事务里,只有当请求完全处理完成(比如返回响应给客户端)后,这个事务才会提交到数据库。也就是说,当你在create视图里调用serializer.save()创建了BankEntry,此时这条数据还处于当前请求的"未提交事务"中,其他进程(比如Celery的worker进程)是看不到的。
而Celery任务是异步执行的,它的worker进程完全独立于Django的请求进程,很可能在当前请求的事务提交之前就开始执行查询了——这时候自然找不到刚创建的那条BankEntry。你说"下一次调用能看到之前的记录",就是因为第一次请求结束后事务已经提交,数据真正持久化到了数据库,后续任务就能读到了。
解决方案1:手动提交事务后触发任务
最简单的处理方式是在视图里手动控制事务,确保数据写入数据库后再调用Celery任务:
from django.db import transaction def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) # 用atomic块包裹创建操作,执行完就提交事务 with transaction.atomic(): instance = serializer.save() # 事务提交后再触发异步任务 async_task = async_create_transactions.delay(instance.pk) return Response(serializer.data, status=status.HTTP_201_CREATED)
解决方案2:使用transaction.on_commit钩子(更优雅)
Django提供了transaction.on_commit方法,它会在当前最外层事务提交成功后,再执行传入的回调函数,完美适配复杂的事务嵌套场景:
from django.db import transaction def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) instance = serializer.save() # 只有事务提交成功后,才会触发Celery任务 transaction.on_commit(lambda: async_create_transactions.delay(instance.pk)) return Response(serializer.data, status=status.HTTP_201_CREATED)
额外优化建议
你可以优化Celery任务里的查询逻辑,用get替代filter.first(),同时捕获不存在的异常并记录日志,方便后续排查问题:
import logging logger = logging.getLogger(__name__) @celery_app.task() def async_create_transactions(entry_id): try: bank_entry = BankEntries.objects.get(pk=entry_id) return bank_entry.create_entries() except BankEntries.DoesNotExist: logger.error(f"Failed to find BankEntry with ID: {entry_id} in async task") return None
内容的提问来源于stack exchange,提问作者comalex3
相关产品推荐
相关产品推荐

