避免或处理" BadRequestError:请求的查询已过期。"?

时间:2016-02-24 05:44:11

标签: python google-app-engine google-cloud-datastore

我使用链式延迟任务和查询游标在app引擎中循环数据。 Python 2.7,使用db(不是ndb)。 E.g。

def loop_assets(cursor = None):

  try:

     assets = models.Asset.all().order('-size')

     if cursor:
        assets.with_cursor(cursor)

     for asset in assets.run():

        if asset.is_special():
           asset.yay = True
           asset.put()

  except db.Timeout:
     cursor = assets.cursor()
     deferred.defer(loop_assets, cursor = cursor,  _countdown = 3, _target = version, _retry_options = dont_retry)
     return

总共运行约75分钟(每项任务约1分钟),然后引发了这个异常:

BadRequestError: The requested query has expired. Please restart it with the last cursor to read more results.

阅读the docs,唯一明确的原因是:

  

新的App Engine版本可能会更改内部实现细节,使依赖于它们的游标无效。如果应用程序尝试使用不再有效的游标,则数据存储区会引发BadRequestError异常。

所以也许发生了什么事,但似乎是一个共同发生的事情,我第一次尝试这种技术时,我发现了内部实施的变化' (除非他们经常发生)。

还有其他解释吗? 有没有办法重新设计我的代码以避免这种情况?

如果没有,我认为唯一的解决方案是标记已处理的资产,然后在查询中添加额外的过滤器以排除这些资产,然后在每次死亡时手动重新启动该过程。

作为参考,this question提出了类似的问题,但接受的答案是使用游标',我已经在做了,所以它不能是同一个问题。

2 个答案:

答案 0 :(得分:1)

您可能需要查看AppEngine MapReduce

  

MapReduce是一种用于处理大量数据的编程模型   以平行和分布的方式。它适用于大型,   长期工作,无法在单一范围内处理   请求,任务如:

     
      
  • 分析应用程序日志
  •   
  • 汇总外部来源的相关数据
  •   
  • 将数据从一种格式转换为另一种格式
  •   
  • 导出数据以进行外部分析
  •   

答案 1 :(得分:0)

当我问这个问题时,我曾经运行过一次代码,并且经历过一次BadRequestError。然后我再次运行它,它完成没有BadRequestError,总共运行了大约6个小时。所以在这一点上我会说最好的解决方案'这个问题是使代码具有幂等性(以便可以重试),然后添加一些代码进行自动重试。

在我的特定情况下,还可以调整查询,以便在光标“到期”的情况下,查询可以在光标停止的情况下重新启动。有效地将查询更改为:

assets = models.Asset.all().order('-size').filter('size <', last_seen_size)

其中last_seen_size是从每个任务传递到下一个任务的值。