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

2024-09-25 00:34:56 发布

您现在位置:Python中文网/ 问答频道 /正文

我使用链式延迟任务和查询游标在appengine中循环数据。Python2.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,唯一说明的原因是:

New App Engine releases may change internal implementation details, invalidating cursors that depend on them. If an application attempts to use a cursor that is no longer valid, the Datastore raises a BadRequestError exception.

所以也许这就是事实,但我第一次尝试这种技术时,我遇到了一个“内部实现的变化”(除非经常发生)。在

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

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

作为参考,this question也提出了类似的问题,但公认的答案是“使用光标”,我已经在做了,所以不可能是同一个问题。在


Tags: thetoloopdbifthat进程is
2条回答

当我问这个问题时,我运行了一次代码,并经历了一次BadRequestError。然后我再次运行它,它没有出现BadRequestError,总共运行了6个小时。所以在这一点上,我想说这个问题的最佳解决方案是使代码幂等(以便可以重试),然后添加一些代码来自动重试。在

在我的具体例子中,还可以对查询进行调整,以便在光标“过期”的情况下,查询可以在光标停止的位置重新启动而不使用光标。有效地将查询更改为:

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

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

您可能需要查看AppEngine MapReduce

MapReduce is a programming model for processing large amounts of data in a parallel and distributed fashion. It is useful for large, long-running jobs that cannot be handled within the scope of a single request, tasks like:

  • Analyzing application logs
  • Aggregating related data from external sources
  • Transforming data from one format to another
  • Exporting data for external analysis

相关问题 更多 >