2014-10-06 2 views
1

В настоящее время я пытаюсь понять очередь задач движка Google (gae).
Как показать прогресс для выполнения задачи очереди задач приложения Google?

У меня есть проблема, которая очень похожа на this

Поэтому я закодированы небольшое приложение в соответствии с решением «Чачан».

Так что моя главная проблема - опросить значение прогресса с сайта 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-loop не смог запустить 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 libs, похоже, не работают должным образом для панели progress. (см 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> 

вы должны ссылаться на Jquery файлы, загруженные из http://jqueryui.com/download/ с выбранной темой UI (без вас не будет видеть ничего)

!

Загрузили zip и ссылайтесь на эти unziped источники jquery в файле «hellogaequeue.py». Ваша структура папок должна выглядеть следующим образом:

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

Смежные вопросы