GAE让任务为用户生成页面

时间:2010-05-17 23:30:37

标签: google-app-engine

我有一个网络应用程序,我希望具有以下功能:

  1. 用户提供网址
  2. webapp从该网址获取json数据,并从同一网站获取其他人(这可能需要1-10秒)
  3. webapp使用数据为用户生成页面
  4. 通过这种方法,我相信如果服务器正在为一个用户获取数据,那么另一个用户将无法加载页面(服务器忙)。如果可能,我想避免这种情况。

    似乎Google Tasks API对此很有用,但我看不到如何运行任务,然后使用任务的输出来生成页面(主应用程序将在何时知道任务完了?)

    解决此问题的最佳方法是什么?

    提前致谢

1 个答案:

答案 0 :(得分:3)

一些想法:

1)App引擎一次可以提供多个请求。尝试一下 - 应用引擎可能会启动多个应用实例=>可以一次完成多个请求。虽然请求时间很长,但我不希望它扩展得太多(他们建议请求/响应时间不到1秒 - see this link)。

2)如果您想快速返回给用户,可以按照建议排队到任务队列。然后让用户的网页(通过元标记http-equiv或JavaScript)每隔几秒轮询一次服务器以查看页面是否准备就绪。

3)如果再次需要生成的页面,您应该考虑对其进行memcaching以尝试再次保存生成它的工作量。加载时间为10秒,您甚至可以考虑将它们存储在数据存储区中一段时间​​(如果缓存适合您的应用)。

以下是如何执行此操作的一个非常基本的示例:

import hashlib

from google.appengine.api.labs import taskqueue
from google.appengine.ext import db, webapp
from google.appengine.ext.webapp.util import run_wsgi_app

class BuiltPage(db.Model):
    html = db.TextProperty()

class PageBuilder(webapp.RequestHandler):
    """Handler called by the task queue to build the page."""
    def post(self):
        key = self.request.get('key')
        url = self.request.get('url')
        import time
        time.sleep(5) # pretend it takes a while to build the page
        html = "you asked for %s" % url # do real stuff to build the page here ...
        BuiltPage(key_name=key, html=html).put() # should check for errors ...

def html_to_redir_to_built_page(hexkey):
    "Page to show while we wait.  Auto-refreshes until we get the built page."""
    new_url = '/get_built_page?k=' + hexkey
    refresh_tag = '<meta http-equiv="refresh" content="2;%s"/>' % new_url
    return '<html><head>%s</head><body>please wait</body></html>' % refresh_tag

class BuildPageForURL(webapp.RequestHandler):
    """Handles requests by a user to build the page for the request URL."""
    def get(self):
        url = self.request.get('url')
        key = hashlib.md5(url).hexdigest()
        # optimization: check datastore to see if it was already generated?
        taskqueue.add(url='/buildit', params=dict(key=key, url=url))
        self.redirect('/get_built_page?k=' + key)

class GetBuiltPage(webapp.RequestHandler):
    """Returns the built page if it is ready, otherwise returns a page which will retry later"""
    def get(self):
        key = self.request.get('k')
        bp = BuiltPage.get_by_key_name(key)
        if bp:
            self.response.out.write(bp.html)
            # maybe cleanup if you know this is a 1-time request: bp.delete()
        else:
            self.response.out.write(html_to_redir_to_built_page(key))

application = webapp.WSGIApplication([('/',               BuildPageForURL),
                                      ('/buildit',        PageBuilder),
                                      ('/get_built_page', GetBuiltPage)])
def main(): run_wsgi_app(application)
if __name__ == '__main__': main()