26

我有一个应用程序涉及定期向约 100 万用户发送 Apple 推送通知。这样做的设置已经针对少量通知进行了构建和测试。由于我无法以这种规模测试发送,因此我很想知道在发送批量推送通知时是否存在任何问题。我有用 Python 编写的脚本,它们打开到推送服务器的单个连接并通过该连接发送所有通知。Apple 建议尽可能长时间保持打开状态。但我也看到连接终止,您需要重新建立它。

总而言之,令人不安的是,成功的发送未被确认,只有错误的发送被标记。从程序员的角度来看,您现在需要注意许多可能出错的事情,而不是简单地检查一件事“如果(成功)”。

我的问题是:您需要注意哪些典型错误,以确保您的消息不会悄无声息地消失在遗忘中?连接关闭很容易。还有其他人吗?

4

2 回答 2

12

我完全同意你的观点,这个 API 非常令人沮丧,如果他们会为每个通知发送响应,它会更容易实现。

也就是说,这就是 Apple 所说的你应该做的事情(来自Technical Note):

推送通知吞吐量和错误检查

使用 APN 没有上限或批量大小限制。iOS 6.1 新闻稿称,APNs 自成立以来已发送超过 4 万亿条推送通知。在 WWDC 2012 上宣布,APN 每天发送 70 亿条通知。

如果您看到吞吐量低于每秒 9,000 条通知,则您的服务器可能会受益于改进的错误处理逻辑。

以下是使用增强的二进制接口时如何检查错误的方法。继续写入,直到写入失败。如果流已准备好再次写入,请重新发送通知并继续。如果流尚未准备好写入,请查看流是否可用于读取。

如果是,请从流中读取所有可用的内容。如果返回零字节,则连接因错误(例如无效的命令字节或其他解析错误)而关闭。如果您返回六个字节,这是一个错误响应,您可以检查响应代码和导致错误的通知的 ID。您需要再次发送该通知之后的所有通知。

发送完所有内容后,请最后一次检查错误响应。

仅仅因为正常的延迟,断开的连接可能需要一段时间才能从 APN 回到您的服务器。由于连接断开,在写入失败之前可以发送超过 500 条通知。大约 1,700 次通知写入可能会因为管道已满而失败,因此在流准备好再次写入时重试。

现在,这里是权衡变得有趣的地方。您可以在每次写入后检查错误响应,并立即发现错误。但这会导致发送一批通知所需的时间大幅增加。

如果您正确捕获了设备令牌并将它们发送到正确的环境,那么设备令牌应该几乎都是有效的。因此,假设故障很少见,进行优化是有意义的。如果您在检查错误响应之前等待写入失败或批处理完成,您将获得更好的性能,甚至计算再次发送丢弃通知的时间。

这些都不是真正特定于 APN 的,它适用于大多数套接字级编程。

如果您选择的开发工具支持多线程或进程间通信,您可以让一个线程或进程一直等待错误响应,并让主发送线程或进程知道何时应该放弃并重试。

于 2013-05-03T16:27:20.630 回答
7

只是想以第一人称视角加入进来,因为我们每天都会发送数百万条 APNS 通知。

不幸的是,@Eran 引用的参考资料是关于 Apple 如何管理 APNS 套接字的最佳资源。对于小批量来说这很好,但 Apple 的文档总体上非常偏向于休闲、小批量的开发人员。一旦扩大规模,您将看到大量未记录的行为。

该文档中关于异步进行错误检测的部分对于高吞吐量至关重要。如果您坚持在每次发送时阻止错误,那么您将需要高度并行化您的工作人员以保持吞吐量。然而,推荐的方法是尽可能快地发送,并且无论何时出现错误:修复和重播。

我反对的那篇文章的一部分是:

如果您正确捕获了设备令牌并将它们发送到正确的环境,那么设备令牌应该几乎都是有效的。因此,假设故障很少见,进行优化是有意义的

用如此巨大的“如果”来预测该建议似乎具有极大的误导性。我几乎可以保证,大多数开发人员都没有 100%“正确”地获取令牌并处理 Apple 的反馈服务。即使它们是,系统本质上是有损的,所以漂移会发生。

我们看到非零数量的错误 #8 响应(无效的设备令牌),我将其归因于有根电话、客户端错误或用户故意将其令牌欺骗给我们。过去我们还看到了一些错误 #7(无效的有效负载大小),我们将其追踪到开发人员在我们端添加的编码不正确的消息。这当然是我们的错,但这是我的观点——说“优化假设失败将是罕见的”是发送给学习开发人员的错误信息。我要说的是:

假设会发生错误。

希望它们不经常发生,但要防御性地编码以防万一。

如果您在假设错误很少见的情况下进行优化,那么每当 APNS 服务出现故障并且您发送的每条消息都返回错误 #10 时,您可能会将基础架构置于风险之中。

当试图弄清楚如何正确响应错误时,麻烦就来了。关于如何正确处理和从不同错误中恢复的文档不明确或不存在。这显然是留给读者的练习。

于 2013-10-05T01:52:29.150 回答