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

查看:218
本文介绍了某些设备未收到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 mili-seconds的潜在错误响应更有效,但您可能会错过错误响应,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%的错误响应(I通过编写模拟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天全站免登陆