我有一个在一个视图上调用的任务。基本上,该任务负责获取一些 pdf 数据,并通过 django 存储将其保存到 s3 中。
这是启动它的视图:
@login_required
@minimum_stage(STAGE_SIGN_PAGE)
def page_complete(request):
if not request.GET['documentKey']:
logger.error('Document Key was missing', exc_info=True, extra={
'request': request,
})
user = request.user
speaker = user.get_profile()
speaker.readyForStage(STAGE_SIGN)
speaker.save()
retrieveSpeakerDocument.delay(user.id, documentKey=request.GET['documentKey'], documentType=DOCUMENT_PAGE)
return render_to_response('speaker_registration/redirect.html', {
'url': request.build_absolute_uri(reverse('registration_sign_profile'))
}, context_instance=RequestContext(request))
这是任务:
@task()
def retrieveSpeakerDocument(userID, documentKey, documentType):
print 'starting task'
try:
user = User.objects.get(pk=userID)
except User.DoesNotExist:
logger.error('Error selecting user while grabbing document', exc_info=True)
return
echosign = EchoSign(user=user)
fileData = echosign.getDocumentWithKey(documentKey)
if not fileData:
logger.error('Error retrieving document', exc_info=True)
else:
speaker = user.get_profile()
print speaker
filename = "%s.%s.%s.pdf" % (user.first_name, user.last_name, documentType)
if documentType == DOCUMENT_PAGE:
afile = speaker.page_file
elif documentType == DOCUMENT_PROFILE:
afile = speaker.profile_file
content = ContentFile(fileData)
afile.save(filename, content)
print "saving user in task"
speaker.save()
与此同时,我的下一个视图命中(实际上它是一个 ajax 调用,但这没关系)。基本上它为下一个嵌入式文档获取代码。一旦它得到它,它就会更新扬声器对象并保存它:
@login_required
@minimum_stage(STAGE_SIGN)
def get_profile_document(request):
user = request.user
e = EchoSign(request=request, user=user)
e.createProfile()
speaker = user.get_profile()
speaker.profile_js = e.javascript
speaker.profile_echosign_key = e.documentKey
speaker.save()
return HttpResponse(True)
我的任务正常工作,并speaker.page_file
正确更新属性。(我可以暂时在管理员中看到这个,也可以在 postgres 日志中看到它。)
但是它很快就被盖住了,我相信get_profile_document
在它更新并保存profile_js
属性后视图中的调用。事实上,我知道这是基于 SQL 语句发生的地方。在 profile_js 更新之前它就在那里,然后它就消失了。
现在我真的不明白为什么。扬声器在每次更新和保存之前被正确获取,并且这里还没有真正的缓存,除非 get_profile() 做了一些奇怪的事情。发生了什么事,我该如何避免这种情况?(另外,我需要在 fileField 上speaker
运行后调用 save onsave
吗?因此,postgres 日志中似乎有重复的调用。
更新
很确定这是由于 Django 的默认视图事务处理。视图开始一个事务,需要很长时间才能完成,然后提交,覆盖我已经在 celery 任务中更新的对象。
我不确定如何解决它。如果我将方法切换为手动事务,然后在获取 echosign js 后立即提交(需要 5-10 秒),它会启动新事务吗?似乎没有工作。
也许不吧
我没有TransactionMiddleware
添加。所以除非它发生了,否则这不是问题。