jquery - 如何显示正在运行的谷歌应用程序引擎任务队列任务的进度?

标签 jquery python google-app-engine

我目前正在尝试了解 Google 应用引擎 (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(..) 函数中,因为这会引发 Deadline超过错误。 我还应该提到 for 循环无法并发运行。

额外信息: 我的 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.) 问题是引用的 Jquery 库似乎无法在进度条上正常工作。 (请参阅this以获得更好的解释)

所以这是“hello 任务队列与 jquery 进度条”应用程序的最终来源:

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 模板(“counter.html”):

<!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/下载的jquery文件具有选定的 UI 主题(没有您将看不到任何内容!)

下载 zip 并在“hellogaequeue.py”文件中引用这些解压缩的 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”技巧(仅在 post-request 之后启动轮询间隔)。 因此,如果有人有更干净的解决方案,我会很高兴看到它。

关于jquery - 如何显示正在运行的谷歌应用程序引擎任务队列任务的进度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26224484/

相关文章:

javascript - 上面显示 input.focus()

javascript - 将列表项图像对齐到 html 中心

python - 如何重复numpy数组中的特定元素?

json - 将 ndb.Model 序列化为 JSON 的 App 引擎数据存储 to_dict 替代方案

javascript - 查看当前页面是否等于相对链接 - JavaScript

javascript - 如何在jquery中查找类型是select还是input

python - 将代码存储在列表或字典中?

python - 如何在 App Engine 中解码 JPG 中的像素(使用纯 python)?

google-app-engine - 关系数据模型到 Google 数据存储映射

node.js - Google App Engine - 具有所有语言环境的 Node.js