奇怪的行为,我不知道如何解释。我有一个模型Track
,其中包含一些相关的points
。我称芹菜任务用点进行一些计算,它们似乎在方法本身完全可达,但在芹菜任务中不可用。
@shared_task
def my_task(track):
print 'in the task', track.id, track.points.all().count()
def some_method():
t = Track()
t.save()
t = fill_with_points(t) # creating points, attaching them to a Track
t.save()
print 'before the task', track.id, track.points.all().count()
my_task.delay(t)
打印以下内容:
before the task, 21346, 2971
in the task, 21346, 0
奇怪的是,当我在my_task
的第一行或者在调用my_task
之前放置time.sleep(10)时,它运作良好,就像有一些竞争条件。但是第一个打印的行明确表示,当points
进行选择查询(track.points.all().count()
)时,{{1}}在数据库中可用。
答案 0 :(得分:3)
我将假设这是由于事务隔离造成的。
默认情况下,Django事务与请求相关联;当事务处于活动状态时,在提交事务之前,其他任何进程都不会看到更改。如果您正处于save方法的中间,并且在请求完成之前发生了很多其他操作,那么Celery可能会在提交事务之前开始处理任务。您可以通过手动提交或延迟任务来解决此问题。
答案 1 :(得分:0)
你永远不应该将模型对象传递给芹菜任务。这是因为与Django应用程序相比,celery任务中的会话可能会过期(或不同),并且此对象将不会链接到会话,因此可能无法使用/ beheave错误。你应该做的是发送id。所以类似于track_id
,然后通过发出查询从数据库中获取对象。这应该最有可能解决你的问题。
@shared_task
def my_task(track_id):
track = Track.query.get(track_id) # Or how ever the query should be
print 'in the task', track.id, track.points.all().count()
def some_method():
t = Track()
t.save()
t = fill_with_points(t) # creating points, attaching them to a Track
t.save()
print 'before the task', track.id, track.points.all().count()
my_task.delay(t.id) # Pass the id here, not the object
答案 2 :(得分:0)
所以,我已经使用django-transaction-hooks解决了这个问题。替换我的数据库后端看起来仍然有点可怕,但是django-celery-transactions
似乎在Django 1.6中被打破了。现在我的设置如下:
settings.py:
DATABASES = {
'default': {
'ENGINE': 'transaction_hooks.backends.postgresql_psycopg2',
'NAME': 'foo',
},
}
SOUTH_DATABASE_ADAPTERS = {'default':'south.db.postgresql_psycopg2'} # this is required, or South breaks
models.py:
from django.db import connection
@shared_task
def my_task(track):
print 'in the task', track.id, track.points.all().count()
def some_method():
t = Track()
t.save()
t = fill_with_points(t) # creating points, attaching them to a Track
t.save()
print 'before the task', track.id, track.points.all().count()
connection.on_commit(lambda: my_task.delay(t))
结果:
before the task, 21346, 2971
in the task, 21346, 2971
这种常见的用例没有本地芹菜或Django解决方案,这似乎仍然很奇怪。