如何显示正在运行的Google App引擎任务队列任务的进度?

时间:2014-10-06 20:37:37

标签: jquery python google-app-engine

我目前正在尝试了解谷歌应用引擎(gae)的任务队列。

我遇到的问题与this

非常相似

因此我根据“chachan”的解决方案编写了一个小应用程序。

所以我的主要问题是如何从html网站轮询进度值。

我写了一个小的“Hello gae任务队列”应用程序,它从用户那里获取一个数字 并打印此数字,使用1到10之间的所有数字进行多次计算。计算由任务队列完成。 来源如下:

#hellogaequeue.py

import os
import time
import webapp2
import jinja2
import logging
import json
from google.appengine.api import taskqueue


template_dir = os.path.join(os.path.dirname(__file__), 'templates')
JINJA_ENV = jinja2.Environment(loader = jinja2.FileSystemLoader(template_dir), autoescape = True)


myresults = []      # the results of the task in a list
myProgressValue = 0 # represents the progess of the task. range[ 0, 100 ]

#define the main handler to show the html-site and post some data to the task.
class MainHandler(webapp2.RequestHandler):
    def get(self):
        #gets the calculated results of the task (therefor empty at first call)
        #and give it to the jinja2 framework to render the html page
        template_values = {'myresults': myresults}
        counter_template = JINJA_ENV.get_template('counter.html')
        self.response.out.write(counter_template.render(template_values))

    # if user clicks the button, we write the data from the input field onto 'key' and
    # than add a new task, with the parameter holding the value of 'key'
    def post(self):
        key = self.request.get('key')

        # Add the task to the default queue.
        taskqueue.add(url='/worker', params={'key': key})
        self.redirect('/')  #calls MainHandler.get(...),  which shows than 'counter.html' again

#define the handler for the task worker
class TaskWorker(webapp2.RequestHandler):
    def post(self): 
        # ensure to use the global variables
        global myresults
        global myProgressValue

        # get the 'params={'key': key}' value
        key = self.request.get('key')

        #now imagine this for loop takes 5 minutes to finish
        #how to show the progress of this loop in 'counter.html'
        for x in xrange(1, 11):
            time.sleep(1)
            res = x*int(key)
            myresults.append(str(res))
            myProgressValue = myProgressValue + 10


class ProgressWorker(webapp2.RequestHandler):
    def get(self):
        global myProgressValue

        logging.info("Call to ProgressHandler. MyProgressValue is = {p}".format(p=myProgressValue))

        json_result = json.dumps({ "progress" : myProgressValue } )
        self.response.headers['Content-Type'] = 'application/json; charset=UTF-8'
        self.response.out.write(json_result)


application = webapp2.WSGIApplication( [ ('/', MainHandler),  ('/worker', TaskWorker), ('/progress', ProgressWorker) ], debug=True)

'counter.html'的来源是:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello gae task queue with jQuery UI Progressbar</title>
    <link rel="stylesheet" href="//code.jquery.com/ui/1.11.1/themes/smoothness/jquery-ui.css">
    <script src="//code.jquery.com/jquery-1.10.2.js"></script>
    <script src="//code.jquery.com/ui/1.11.1/jquery-ui.js"></script>
</head>
<body>
    <form action="/" method="POST">
        <input type="text" name="key" id="key">
        <input type="submit" value="start gae task">
    </form>

    {% for counter in myresults %}
        <li>
         {{counter}}
        </li>
    {% endfor %}

    <div id="progressbar"></div>

    <div id="dbg"></div>

    <script>
        function refresh() 
        {
            var progressVal = 0

            $.ajax(
            {
                type: 'GET',
                url: '/progress',
                success: function(data) 
                {
                    var obj = JSON.parse(data);
                    progressVal = obj.progress;
                    document.getElementById("dbg").innerHTML = obj.progress;
                },
                error: function(xhr, status, error) 
                {
                    alert(xhr.status);
                    alert(error);
                }
            });

            $( "#progressbar" ).progressbar(
            {
                value: progressVal
            });
        }

        $(function()
        {
            setInterval("refresh()", 3000);
        });
    </script>
</body>
</html>

所以,第一个问题是:
为什么jquerys progressbar不起作用? (没有警报。) 我做错了什么?

第二个问题是:
这是正确的方法吗?
考虑到for循环花费的时间超过60秒。因此无法将其放在MainHandler.post(..)函数中,因为这将导致截止日期超出错误。 我还应该提到for循环不能运行Concurrent。

额外信息: 我的gae项目的文件夹结构是:

hellogaequeue
    -templates
         -counter.html
    -app.yaml
    -hellogaequeue.py
    -queue.yaml

,app.yaml看起来像:

application: queuetest-app-id
version: 1
runtime: python27
api_version: 1
threadsafe: true

libraries:
- name: jinja2
  version: latest

handlers:
- url: /.*
  script: hellogaequeue.application

1 个答案:

答案 0 :(得分:1)

我终于开始工作了。

1。)问题是引用的Jquery库似乎无法正常进行进度条。 (有关更好的解释,请参阅this

所以这里是&#34;你好任务队列的最终来源,而jquery进度条&#34;应用程式:

import os
import time
import webapp2
import jinja2
import json
from google.appengine.api import taskqueue

template_dir = os.path.join(os.path.dirname(__file__), 'templates')
JINJA_ENV = jinja2.Environment(loader = jinja2.FileSystemLoader(template_dir), autoescape = True)


myresults = []
myProgressValue = 0 #range[ 0, 100 ]


class MainHandler(webapp2.RequestHandler):
    def get(self):
        template_values = {'myresults': myresults, 'progressScriptActive':False}
        counter_template = JINJA_ENV.get_template('counter.html')
        self.response.out.write(counter_template.render(template_values))

    def post(self):
        key = self.request.get('key')
        # Add the task to the default queue.
        taskqueue.add(url='/worker', params={'key': key})

        template_values = {'myresults': myresults, 'progressScriptActive':True}
        counter_template = JINJA_ENV.get_template('counter.html')
        self.response.out.write(counter_template.render(template_values))


class TaskWorker(webapp2.RequestHandler):
    def post(self): 
        global myresults
        global myProgressValue

        key = self.request.get('key')
        for x in xrange(1, 11):
            time.sleep(1)
            res = x*int(key)
            myresults.append(str(res))
            myProgressValue = myProgressValue + 10


class ProgressWorker(webapp2.RequestHandler):
    def get(self):
        global myProgressValue

        json_result = json.dumps( myProgressValue )
        self.response.headers['Content-Type'] = 'application/json; charset=UTF-8'
        self.response.out.write(json_result)


application = webapp2.WSGIApplication(
    [
        ('/', MainHandler),
        ('/worker', TaskWorker),
        ('/progress', ProgressWorker)
    ], debug=True)

和HTML jinja2模板(&#34; counter.html&#34;):

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello gae task queue with jQuery UI Progressbar</title>
    <script src="/static/external/jquery/jquery.js"></script>
    <script src="/static/jquery-ui.js"></script>
    <link href="/static/jquery-ui.css" rel="stylesheet">
</head>
<body>
    <form action="/" method="POST">
        <input type="text"  name="key" id="key">
        <input type="submit"  value="start gae task">
    </form>

    {% for counter in myresults %}
        <li>
         {{counter}}
        </li>
    {% endfor %}

    <div id="progressbar"></div>
    <div id="dbg"></div>

<script> 

    var intervalHandler = 0;

    function refresh() 
    {
        $.ajax(
        {
            type: 'GET',
            url: '/progress',
            success: function(data) 
            {   
                var progressVal = $.parseJSON( data );
                document.getElementById("dbg").innerHTML = progressVal;   

                if( progressVal > 99 )
                {
                    $( "#progressbar" ).progressbar( { value: 100 });
                    alert("Finish");

                    clearInterval(intervalHandler); // stop the interval
                    intervalHandler = null;

                    //window.location.reload(true);// will perform a post request,  but we need a GET request
                    var loc = window.location;
                    window.location = loc.protocol + '//' + loc.host + loc.pathname + loc.search;
                 }
                else
                {
                    $( "#progressbar" ).progressbar( { value: progressVal });
                }
            },
            error: function(jqXHR, textStatus, errorThrown)
            {
                alert("Request Error !!!!");
            }
        });
    };

{% if progressScriptActive %}
    $(function()
    {
        intervalHandler = setInterval("refresh()", 2000);
    });
{% endif %}
</script>
</body>
</html>

您必须引用从http://jqueryui.com/download/下载的具有选定UI主题的jquery文件(不会看到任何内容!)

下载了zip并在&#34; hellogaequeue.py&#34;中引用了这些解压缩的jquery源代码。文件。 您的文件夹结构应如下所示:

hellogaequeue
    -templates
         -counter.html
    -static
         - jquery-ui.css
         - jquery-ui.js
         - ... and all the other unziped files/folders
    -app.yaml
    -hellogaequeue.py
    -queue.yaml 

并且对于app.yaml,你必须添加:

handlers:
- url: /static
  static_dir: static

我知道这不是一个干净的解决方案,因为'progressScriptActive&#39;技巧(仅在后请求后启动轮询间隔)。 因此,如果某人有更清洁的解决方案,我会很高兴看到它。