我有一个网络应用程序,我希望具有以下功能:
通过这种方法,我相信如果服务器正在为一个用户获取数据,那么另一个用户将无法加载页面(服务器忙)。如果可能,我想避免这种情况。
似乎Google Tasks API对此很有用,但我看不到如何运行任务,然后使用任务的输出来生成页面(主应用程序将在何时知道任务完了?)
解决此问题的最佳方法是什么?
提前致谢
答案 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()