I asked a similar question on how to detect and report when a celery task is completed (or has failed). That question focused on how to do this using the Django messages framework, which turned out to be unnecessary for my purposes. My current approach is to simply send a JSON HttpResponse instead, and render a success or failure message based on the JSON received. Below is my code to poll the state of a task:
views.py:
def poll_state(request):
if request.is_ajax():
if 'task_id' in request.POST.keys() and request.POST['task_id']:
task_id = request.POST['task_id']
task = AsyncResult(task_id)
if task.successful():
logger.debug("Successful upload")
return HttpResponse(json.dumps({"message":"Upload successful!", "state":"SUCCESS"}), content_type='application/json')
elif task.failed():
logger.debug("Error in upload")
return HttpResponse(json.dumps({"message":"Error in upload!", "state":"FAILURE"}), content_type='application/json')
else:
logger.info('No task_id in the request')
else:
logger.info('Not an ajax request')
result = task.result
state = task.state
response = {}
response["percent"] = result["percent"]
response["state"] = state
json_data = json.dumps(response)
return HttpResponse(json_data, content_type='application/json')
And the corresponding jQuery (and Django templating):
{% if task_id %}
var PollState = function(task_id) {
jQuery.ajax({
url: "poll_state",
type: "POST",
data: "task_id=" + task_id,
}).done(function(task) {
if (task.percent) {
console.log(task.percent);
jQuery('.bar').css({'width': task.percent + '%'});
jQuery('.bar').html(task.percent + '%');
}
else if (task.state == "SUCCESS" || task.state == "FAILURE") {
console.log(task.state);
jQuery('.status').html(task);
};
else {
jQuery('.status').html(task);
}
setTimeout(function () {
PollState(task_id);
}, 300);
});
}
PollState('{{ task_id }}');
{% endif %}
And below is the code for the task itself:
tasks.py:
@task(base=DBTask) # a custom base task class
def upload_task(datapoints, user, description): # datapoints is a list of dictionaries, user and description are strings
from utils.db.databaseinserter import insertIntoDatabase
for dp_count in insertIntoDatabase(datapoints, user, description): # insertIntoDatabase yields the number of datapoints inserted into the database so far at the end of each iteration
percent_completion = int(100 * (float(dp_count) / float(len(datapoints))))
current_task.update_state(state='PROGRESS', meta={'percent':percent_completion})
What happens is that if an upload is successful, then once the upload is complete, the console logs are cluttered with the JSON success message. And if an upload has an error, then reloading will clutter the logs with the error message. In both cases, poll_state
is continuously sending the HttpResponse of success or failure. Additionally, after starting a new task, I still have the old task info being sent rather than the current one. The only time the current task info is received is the first task when the server is first started; any polling of subsequent tasks will only get the very first task's info.
What am I doing wrong here? I've been scratching my head at this for a while now but can't figure it out. The end goal here is to display some sort of notification of completion of a task or failure of a task on the web page, and to not have the success/failure HttpResponse repeatedly sent after completion.
I've tried deleting the task_id session key in the task.successful()
and task.failed()
blocks in poll_state
. This does prevent the success/failure HttpResponse from being repeatedly sent, but I still have the problem of subsequent tasks not having their HttpResponse sent; what happens is that once a new task is started after the first one, the HttpResponse for the very first task is sent, and the percent tracking of the current task no longer works.
答案 0 :(得分:1)
经过多年的努力和奋斗,事实证明我所有问题的答案实际上是一条线。
这个特殊问题的解决方案是改变
task_id = request.POST['task_id']
到
task_id = request.session['task_id']
poll_state
中的。