2014-10-06 62 views
1

我目前尝试了解谷歌应用程序引擎(gae)的任务队列。
如何显示正在运行的Google应用引擎任务队列任务的进度?

我有一个问题,这是非常类似于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循环无法运行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

我终于得到它的工作。

1.)问题是引用的Jquery库似乎无法正常工作进度条。 (见this一个更好的解释)

因此,这里是一个的“你好任务队列蒙山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/与选定的UI主题(没有你看不到任何下载jQuery的文件)

下载了zip文件,并在“hellogaequeue.py”文件中引用了这些unziped 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 

和为应用程序。YAML你必须添加:

handlers: 
- url: /static 
    static_dir: static 

我知道这是不是一个干净的解决方案,因为“progressScriptActive”绝招(只启动一个轮询后请求后INTERVALL)。 所以如果有人有一个更清洁的解决方案,我会很高兴看到它。

+0

myProgressValue应该保存在gae的数据库中。由于Google会启动应用程序的新实例,因此所有全局参数都将重置为初始值。 GAE日志说:“这个请求导致你的应用程序开始一个新的进程, ,因此导致你的应用程序代码被首次加载。 这个请求可能需要更长的时间,并且使用比典型的请求更多的CPU你的申请。” – user1911091 2014-10-15 06:18:23

相关问题