处理Google App Engine上的db.Timeout

4 投票
4 回答
1289 浏览
提问于 2025-04-15 14:29

我正在测试我的应用程序(在Google App Engine的在线服务器上),我写的代码里大约有40个db.GqlQuery()的语句(大部分是类的一部分)。

不过,我经常遇到db.Timeout的错误。

我该怎么处理这个问题呢?我打算用一些比较狠的代码把所有的查询包起来,像这样:

  querySucceeded = False
  while not querySucceeded :
    try :
      result = db.GqlQuery( """xxx""" ).get()
      querySucceeded = True #only get here if above line doesn't raise exc
    except :
      querySucceeded = False

这样做可以吗?你觉得怎么样?有没有更好的方法来处理db.Timeout的问题?

编辑:

现在我对任何获取查询都使用这个:

""" Query gets single result """
def queryGet( gql ) :
  querySucceeded = False
  while not querySucceeded :
    try :
      result = db.GqlQuery( gql ).get()
      querySucceeded = True #only get here if above line doesn't raise
    except :
      querySucceeded = False
  
  return result

我还有类似的函数用于获取和计数。

4 个回答

2

看看这个关于Python自动重试数据存储超时的教程。这个方法和moraes的回答类似,但你只需要在初始化的时候调用一次,而不是给每个进行数据存储操作的函数加装饰器。

http://appengine-cookbook.appspot.com/recipe/autoretry-datastore-timeouts

7

这里有一个装饰器,用来在遇到数据库超时(db.Timeout)时重试,这个装饰器是从Kay框架中改编而来的:

import logging, time
from google.appengine.ext import db

def retry_on_timeout(retries=3, interval=1.0, exponent=2.0):
    """A decorator to retry a given function performing db operations."""
    def _decorator(func):
        def _wrapper(*args, **kwargs):
            count = 0
            while True:
                try:
                    return func(*args, **kwargs)
                except db.Timeout, e:
                    logging.debug(e)
                    if count >= retries:
                        raise e
                    else:
                        sleep_time = (exponent ** count) * interval
                        logging.warning("Retrying function %r in %d secs" %
                            (func, sleep_time))
                        time.sleep(sleep_time)
                        count += 1

        return _wrapper

    return _decorator

使用这个装饰器很简单,只需要把它加在任何进行数据库操作的函数上,这样在出错时就会自动重试:

@retry_on_timeout()
def do_the_stuff(models):
    return db.put(models)
6

有时候,查询会失败。你可以选择给用户显示一个错误信息,或者像上面那样重试。如果你选择重试,记得使用thread.sleep来增加每次重试之间的等待时间,比如第一次等50毫秒,然后每次都加长一点。这样重试成功的几率会更高,因为如果你一直快速重试,成功的机会反而会降低。

每个请求有40个查询,这可真是很多。你应该考虑重新整理一下你的代码,应该有办法把大部分查询去掉!

撰写回答