我有一个使用Celery + RabbitMQ的Django站点作为长时间运行任务的任务队列。我将结果存储在Redis中。我已经能够使用Celery的update_state
在引导程序进度条中显示一个任务的进度,并通过按钮向Redis DB执行ajax发布以检索当前状态。
理想情况下,我想展示当前正在运行或最近完成的每个任务,这些任务都在Redis中,并且有自己的进度条。目前,我只能通过我的小Click Here
按钮显示当前任务的进度。
我曾尝试为进度条创建多个类,但说实话,我对如何执行此操作感到迷茫,似乎无法找到有关如何执行此类操作的任何内容。我试图尽可能多地上传我的代码。任何帮助将不胜感激!
urlpatterns = [
url(r'^poll_state$', poll_state, name="poll_state"),
url(r'^do_task$', do_task, name="do_task"),
]
from django.shortcuts import render
import json
from celery.result import AsyncResult
from django.shortcuts import render_to_response
from django.http import HttpResponse
from django.views.generic.base import View
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def do_task(request):
data = 'Fail'
if request.is_ajax():
job = add.delay()
request.session['task_id'] = job.id
data = job.id
else:
data = 'This is not an ajax request!'
json_data = json.dumps(data)
return HttpResponse(json_data, content_type='application/json')
@csrf_exempt
def poll_state(request):
""" A view to report the progress to the user """
data = 'Fail'
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)
data = task.info
else:
data = 'No task_id in the request'
else:
data = 'This is not an ajax request'
json_data = json.dumps(data)
return HttpResponse(json_data, content_type='application/json')
from __future__ import absolute_import, unicode_literals
from celery import shared_task
from celery.decorators import task
from celery import current_task
from celery.result import AsyncResult
import celery
from .celery import app
import time
#Task loops every half second to update the current state
@task(bind=True, ignore_result=True)
def add(self):
for i in range(101):
time.sleep(0.5)
self.update_state(state="PROGRESS", meta={'current': i, 'total': 100})
from __future__ import absolute_import, unicode_literals
import os
from celery import Celery
from django.conf import settings
# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'yodaclaw.settings')
app = Celery('myAppName')
# Using a string here means the worker doesn't have to serialize
# the configuration object to child processes.
# - namespace='CELERY' means all celery-related configuration keys
# should have a `CELERY_` prefix.
app.config_from_object('django.conf:settings', namespace='CELERY')
# Load task modules from all registered Django app configs.
# This allows you in shell to not have to import yodaclaw.tasks
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
@app.task
def debug_task(self):
print('Request: {0!r}'.format(self.request))
# Celery Settings
CELERY_BROKER_URL = 'amqp://localhost'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'
CELERY_ACCEPT_CONTENT = ['application/json']
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_TRACK_STARTED = True
{% load static %}
<!DOCTYPE html>
<html>
<head>
{% block title_outer %}
{% endblock %}
{% block meta %}
<meta charset="utf-8">
<meta http-equiv="X-UA-COMPATIBLE" content="IE=edge">
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
{% endblock %}
{% block stylesheets %}
{% endblock %}
{% block javascript %}
{% endblock %}
{% block extra_head %}
{% endblock %}
</head>
<body>
{% block body %}
<div class="wrapper">
{% block nav_header %}
{% endblock %}
{% block nav_sidebar %}
{% endblock %}
{% block content_wrapper %}
<div class="content-wrapper">
{% block content_header %}
<section class="content-header">
</section>
{% endblock %}
{% block content_outer %}
<section class="content">
{% block messages %}
{% endblock %}
{% block content_block_wrap %}
{% block content %}{% endblock %}
{% endblock %}
</section>
{% endblock %}
{% endblock content_wrapper %}
{% block nav_footer %}
{% endblock %}
</div>
<!-- The Right Sidebar -->
<aside class="control-sidebar control-sidebar-light">
<!-- Content of the sidebar goes here -->
{% if task_id %}
<h6>Task ID: {{ task_id }}</h6>
<div class="progress">
<div class="progress-bar progress-bar-success progress-bar-striped" role="progressbar"
aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">
{% if task_id %} {{ task_id }} {% endif %}
</div>
</div>
{% endif %}
<div id="container">
<div id="action">
<button id="do-task">Click here!</button>
</div>
</div>
<!-- Ajax Post to poll_state -->
{% if task_id %}
<script type="text/javascript">
jQuery(document).ready(function() {
var PollState = function(task_id) {
jQuery.ajax({
url: "poll_state",
type: "POST",
data: "task_id=" + task_id,
}).done(function(task) {
if (task.current) {
jQuery('.progress-bar').css({'width': task.current + '%'});
jQuery('.progress-bar').html(task.current + '%');
}
else {
jQuery('.status').html(task);
};
PollState(task_id);
});
}
PollState('{{ task_id }}');
})
</script>
{% endif %}
<!-- Clickable button for do_task -->
<script type="text/javascript">
jQuery('#do-task').click( function() {
jQuery.ajax({
url: "do_task",
data: {},
success: function(){
jQuery.ajax({
url: "",
context: document.body,
success: function(s, x) {
jQuery(this).html(s);
}
});
}
})
});
</script>
</aside>
<!-- The sidebar's background -->
<!-- This div must placed right after the sidebar for it to work-->
<div class="control-sidebar-bg"></div>
{% endblock body %}
</body>
{% block extra_foot %}{% endblock %}
</html>
答案 0 :(得分:0)
签出celery-progress,应该可以处理这个问题。它应该简单到将不同的任务ID放入前端并将每个ID与不同的div相关联的程度。例如。像这样的东西:
var progressUrl1 = "{% url 'celery_progress:task_status' task_id1 %}";
var progressUrl2 = "{% url 'celery_progress:task_status' task_id2 %}";
document.addEventListener("DOMContentLoaded", function () {
CeleryProgressBar.initProgressBar(progressUrl1);
CeleryProgressBar.initProgressBar(progressUrl2);
});
demo page linked from the readme上有许多不同的进度条。