1

我想让我的 Google App Engine 服务中的 db.put() 操作尽可能有弹性,即使在基础设施出现问题或过载的情况下也能最大限度地提高成功的可能性。我目前想出的是捕捉所有可能发生的异常,并创建一个任务,如果第一次尝试失败,则重试提交:

try:
    db.put(new_user_record)
except DeadlineExceededError:
    deferred.defer(db.put,new_user_record)
except:
    deferred.defer(db.put,new_user_record)

此代码是否捕获所有可能的错误路径?或者是否有其他方法 db.put() 可能会失败而不会被此代码捕获?


2013 年 3 月 28 日编辑 - 澄清预期失败的时间

到目前为止,似乎答案假设如果 db.put() 失败,那是因为数据存储已关闭。根据我运行相当高工作负载应用程序的经验,这不一定是必需的。有时您会遇到特定于工作负载的 API 瓶颈,有时一个 API 的缓慢会导致另一个 API 的请求截止日期到期。即使此类事件的频率较低,但如果流量很高,它们的数量可能会很大。这些是我试图涵盖的情况。

4

3 回答 3

1

我不会说这是最好的方法 - 任何导致原始异常的原因都可能再次发生。为了获得额外的弹性,我要做的是首先将要保存的记录加载到内存缓存中,如果 put 发生异常(任何异常),它可以尝试一定次数的重试(例如 3 次),每次重试之间都有短暂的睡眠试图。根据您的应用程序,这可以是同步操作,也可以是使用延迟任务,它可以使用内存缓存中的数据异步完成。
最后,我实际上会对数据存储中的记录进行查询,即使没有异常来确认该行实际上已被写入。

于 2013-03-27T02:55:01.570 回答
1

好吧,我认为尝试这样的回退根本不是一个好主意。如果数据存储已关闭,则它已关闭并且您不走运(不应该经常发生:)对您的代码的一些想法:

  • 在 put 操作期间可能会引发更多异常(例如 InternalError、Timeout、CommittedButStillApplying、TransactionFailedError),其中一些并不意味着 put 失败。(即 CommittedButStillApplying 只是意味着放置操作被延迟)。使用您的方法,在延迟调用成功后,您最终会在数据存储中两次获得该条目。
  • 任务限制在 ~100KB(总大小,不是有效负载)。如果您的有效负载接近或高于该限制,则 deferred-api 将自动尝试将您的有效负载序列化到数据存储区,以使任务本身低于该限制。如果数据存储真的不可用,这也会失败。

因此,最好捕获数据存储错误,并通知您的用户他的请求失败。

于 2013-03-27T14:52:36.903 回答
0

重试一切都很好,但是使用指数退避和最重要的正确事务使用,以便失败 xoesnt 最终导致 oa 部分写入。

于 2013-03-30T05:16:26.560 回答