某些设备未收到 Apple 推送通知 [英] Some Devices Not Receiving Apple Push Notifications

查看:31
本文介绍了某些设备未收到 Apple 推送通知的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 Apples iOS 增强通知格式批量发送推送通知,并使用本文中描述的 PHP 解决方案:https://stackoverflow.com/a/10059000/300129

I am using Apples iOS Enhanced Notification Format to send push notification in bulk, and using the PHP solution described in this post: https://stackoverflow.com/a/10059000/300129

此时的经验是,当我发送推送通知时,有些设备正在接收消息,有些设备则没有.结果不一致.有时设备 X 会收到通知,有时设备 X 不会.我正在记录所有内容,但没有收到任何错误响应.

The experience at this point is that when I send a push notification, some devices are receiving the message and some devices are not. The results are inconsistent. Sometimes device X will receive a notification and sometimes device X will not. I am logging everything and I am not getting any error responses.

任何关于正在发生的事情的想法都会非常有帮助.

Any thoughts about what is happening would be very helpful.

推荐答案

您链接到的答案中的解决方案有问题.它尝试在发送每条消息后读取错误响应,但读取会立即返回并且不会等待响应变为可用.虽然这比在每条消息后等待 X 毫秒的潜在错误响应更有效,但您可能会错过错误响应,并且 Apple 可能会在您不知道发生任何错误的情况下断开连接.

The solution in the answer you linked to has a problem. It attemps to read the error response after each message is sent, but the read returns immediately and doesn't wait for a response to become available. While this is more efficient than waiting for a potential error response for X mili-seconds after each message, you might miss the error response and the connection may be dropped by Apple without you knowing any error occured.

虽然我不能给你代码来解决你的问题,但我可以给你一些建议.

While I can't give you code to solve your problem, I get give you some advice.

这是您应该使用的逻辑(根据 Apple 的说法),但我还没有设法让它可靠地工作(至少在我的 Java 实现中不是这样):

Here's the logic you should use (according to Apple), but I haven't managed to make it work reliably (at least not in my Java implementation):

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

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

If you're seeing throughput lower than 9,000 notifications per second, your server might benefit from improved error handling logic.

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

Here's how to check for errors when using the enhanced binary interface. Keep writing until a write fails. If the stream is ready for writing again, resend the notification and keep going. If the stream isn't ready for writing, see if the stream is available for reading.

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

If it is, read everything available from the stream. If you get zero bytes back, the connection was closed because of an error such as an invalid command byte or other parsing error. If you get six bytes back, that's an error response that you can check for the response code and the ID of the notification that caused the error. You'll need to send every notification following that one again.

发送完所有内容后,最后检查是否有错误响应.

Once everything has been sent, do one last check for an error response.

由于正常延迟,断开的连接可能需要一段时间才能从 APN 返回到您的服务器.在由于连接断开而导致写入失败之前,可以发送 500 多个通知.大约 1,700 次通知写入可能会因为管道已满而失败,因此在这种情况下,请在流准备好再次写入后重试.

It can take a while for the dropped connection to make its way from APNs back to your server just because of normal latency. It's possible to send over 500 notifications before a write fails because of the connection being dropped. Around 1,700 notifications writes can fail just because the pipe is full, so just retry in that case once the stream is ready for writing again.

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

Now, here's where the tradeoffs get interesting. You can check for an error response after every write, and you'll catch the error right away. But this causes a huge increase in the time it takes to send a batch of notifications.

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

Device tokens should almost all be valid if you've captured them correctly and you're sending them to the correct environment. So it makes sense to optimize assuming failures will be rare. You'll get way better performance if you wait for write to fail or the batch to complete before checking for an error response, even counting the time to send the dropped notifications again.

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

None of this is really specific to APNs, it applies to most socket-level programming.

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

If your development tool of choice supports multiple threads or interprocess communication, you could have a thread or process waiting for an error response all the time and let the main sending thread or process know when it should give up and retry.

这是摘自 Apple 的技术说明:推送通知疑难解答.

This is taken from Apple's Tech Note: Troubleshooting Push Notifications.

我不知道你是如何在PHP中检测到写入失败的,但是当它发生时,您应该尝试再次写入失败的通知,如果再次失败,请尝试读取错误响应并关闭连接.

I don't know how you detect in PHP that the write failed, but when it does, you should attempt to write the failed notification once again, and if it fails again, try to read the error response and close the connection.

如果您设法阅读错误响应,您就会知道哪个通知失败了,并且您会知道错误类型(最可能的错误是 8 - 无效的设备令牌).您提到的答案中的代码在识别出该错误后没有做任何事情.如果在写入 100 条消息后收到第 80 条消息的错误响应,则必须重新发送 81 至 100 条消息,因为 Apple 从未收到它们.在我的情况下(Java 服务器),我并不总是设法读取错误响应(有时我在尝试从套接字读取响应时遇到错误).在这种情况下,我只能继续发送下一个通知(并且无法知道 Apple 实际收到了哪些通知).这就是为什么保持数据库中没有无效令牌很重要的原因.

If you manage to read the error response, you will know which notification failed and you'll know the error type (the most likely error is 8 - invalid device token). The code in the answer you referred to doesn't do anything after identifying that error. If after writing 100 messages you get an error response for the 80th message, you must resend messages 81 to 100, since Apple never received them. In my case (Java server), I don't always manage to read the error response (sometimes I get an error when trying to read the response from the socket). In that case I can only move on an send the next notifications (and have no way of knowing which notifications were actually received by Apple). That's why it's important to keep your database clean of invalid tokens.

如果您保持数据库干净(即仅存储 Apple 发送到您的应用程序的设备令牌,并且它们都属于同一个推送环境 - 沙箱或生产),您应该不会遇到任何无效的设备令牌.

If you keep your database clean (i.e. store in it only device tokens that were sent to your App by Apple, and all of them belong to the same push environment - either sandbox or production), you shouldn't encounter any invalid device tokens.

在 Java 中实现推送通知服务器端时,我遇到了与您类似的问题.我无法可靠地获得 Apple 返回的所有错误响应.

I encountered a similar problem to yours when implementing the push notification server side in Java. I couldn't reliably get all the error responses returned by Apple.

我发现在 Java 中有一种方法可以禁用 TCP Nagle 的算法,这会导致在将多个消息批量发送到 Apple 之前对其进行缓冲.尽管 Apple 鼓励我们使用 Nagle 的算法(出于性能原因),但我发现当我禁用它然后尝试在我发送给他们的每条消息后读取 Apple 的响应时,我设法收到了 100% 的错误响应(我写了一个模拟APNS服务器的流程验证了下)

I found that in Java there's a way to disable the TCP Nagle's algorithm, which causes the buffering of multiple messages before sending them in a batch to Apple. Though Apple encourages us to use Nagle's algorithm (for performance reasons), I found that when I disable it and then try to read the response from Apple after each message I send to them, I manage to receive 100% of the error responses (I verified it by writing a process that simulated the APNS server).

通过禁用 Nagle 算法并缓慢地逐个发送通知,并尝试在每条消息后读取错误响应,您可以找到数据库中的所有无效令牌并将其删除.一旦您知道您的数据库是干净的,您就可以启用 Nagle 的算法并快速恢复发送通知,而无需费心阅读 Apple 的错误响应.然后,每当您在向套接字写入消息时遇到错误,您只需创建一个新套接字并重试仅发送最后一条消息即可.

By disabling Nagle's algorithm and sending the notifications one by one, slowly, and atempting to read the error response after each message, you can locate all the invalid tokens in your DB and remove them. Once you know your DB is clean you can enable Nagle's algorithm and resume sending notifications quickly without bothering to read the error responses from Apple. Then, whenever you get an error while writing a message to the socket, you can simply create a new socket and retry sending only the last message.

这篇关于某些设备未收到 Apple 推送通知的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆