原问题
我有一个正在升级的web应用程序的工作版本,我遇到了一个问题:在单个HTTP请求期间执行的任务需要太长的时间。该应用程序通过HTTP Post操作从JavaScript前端获取JSON列表,并返回该列表的已排序/已切片版本。随着输入列表的长度增加,排序操作的执行时间变得更长(显然),因此在长度合适的输入列表上,我会遇到60秒的HTTP请求超时,导致应用程序失败。
我想开始使用deferred库来执行排序任务,但我不清楚如何在执行该任务后存储/检索数据。以下是我的当前代码:
class getLineups(webapp2.RequestHandler):
def post(self):
jsonstring = self.request.body
inputData = json.loads(jsonstring)
playerList = inputData["pList"]
positions = ["QB","RB","WR","TE","DST"]
playersPos = sortByPos(playerList,positions)
rosters, playerUse = getNFLRosters(playersPos, positions)
try:
# This step is computationally expensive, it will fail on large player lists.
lineups = makeLineups(rosters,playerUse,50000)
self.response.headers["Content-Type"] = "application/json"
self.response.out.write(json.dumps(lineups))
except:
logging.error("60 second timeout reached on player list of length:", len(playerList))
self.response.headers["Content-Type"] = "text/plain"
self.response.set_status(504)
app = webapp2.WSGIApplication([
('/lineup',getLineups),
], debug = True)
理想情况下,我希望用延迟任务库调用来替换整个try/except块:
deferred.defer(makeLineups,rosters,playerUse,50000)
但我不确定如何从该操作中获取结果。 我认为我必须将其存储在Datastore中,然后检索它,但是我的JavaScript前端如何知道操作何时完成? 我已经阅读了Google网站上的文档,但仍然不清楚如何完成此任务。
我的解决方法
使用接受答案中的基本概述,以下是我解决这个问题的方法:
def solveResult(result_key):
result = result_key.get()
playersPos = sortByPos(result.playerList, result.positions)
rosters, playerUse = getNFLRosters(playersPos,result.positions)
lineups = makeLineups(rosters,playerUse,50000)
storeResult(result_key,lineups)
@ndb.transactional
def storeResult(result_key,lineups):
result = result_key.get()
result.lineups = lineups
result.solveComplete = True
result.put()
class Result(ndb.Model):
playerList = ndb.JsonProperty()
positions = ndb.JsonProperty()
solveComplete = ndb.BooleanProperty()
class getLineups(webapp2.RequestHandler):
def post(self):
jsonstring = self.request.body
inputData = json.loads(jsonstring)
deferredResult = Result(
playerList = inputData["pList"],
positions = ["QB","RB","WR","TE","DST"],
solveComplete = False
)
deferredResult_key = deferredResult.put()
deferred.defer(solveResult,deferredResult_key)
self.response.headers["Content-Type"] = "text/plain"
self.response.out.write(deferredResult_key.urlsafe())
class queryResults(webapp2.RequestHandler):
def post(self):
safe_result_key = self.request.body
result_key = ndb.Key(urlsafe=safe_result_key)
result = result_key.get()
self.response.headers["Content-Type"] = "application/json"
if result.solveComplete:
self.response.out.write(json.dumps(result.lineups))
else:
self.response.out.write(json.dumps([]))
Javascript前端会在固定的时间内轮询queryLineups URL,如果时间限制到期或接收到数据,则停止轮询。希望这对那些试图解决类似问题的人有所帮助。如果出现问题,我还需要做一些工作来使其优雅地失败,但这个方法有效,只需要改进。