How to reliably and efficiently read all error res

2019-04-16 01:59发布

问题:

I am researching server side development of Apple Push Notifications in Java. I am using the enhanced format, in order to detect failed messages and resend messages that follow bad messages. I know that Apple to not guarantee the delivery of Push Notifications, but I wish to be able to know whether Apple received my messages and whether the contained any errors.

I noticed that when I try to send an invalid message (invalid device token, too large payload, etc...) to Apple, I can send several more messages before the socket is closed. When the socket is closed it's too late to read the error codes from Apple, so I have no idea which message was the bad one (or even if there was a bad message, since Apple say the connection may close occasionally even when there is no error).

The approach I've seen in the source of JavaPNs to handle this is to read responses from Apple immediately after each message (or group of messages) are sent. The reading from the socket if performed frequently, and waits for a timeout in case there is nothing to read. This is acceptable if you send push notifications infrequently.

If you try to send a large number of notifications in a high frequency (lets say hundreds per second), you can't stop after each message to wait for responses from Apple (even if you wait for a response only for 20ms, that would limit you to 50 messages per second, and you have no way of knowing how long it would take Apple to write the error response, so a short wait may not be enough). If you don't stop to read possible errors after each message, you risk your connection being closed during the sending of messages to Apple, in which case you won't be able to get the Id of the message that caused the connection to close.

Another approach I'm considering is to perform the reads and the writes in separate threads. This way I have a much better chance of getting the error messages from Apple (before the connection is closed) without compromising the speed in which I send messages to Apple. This approach is more complicated programmatically, and since my server is expected to send APNs to multiple iOS applications, each requiring its own socket and reader/writer threads, this will increase the number of threads I need by a factor of two.

All of the above described behavior of the APN Server was learned while attempting to send push notifications to Apple's sandbox server. I'm not sure if the behavior of Apple's production server is better, and I'm not sure it's a good idea to perform my tests on the production server.

My question - Is there a way to reliably read the error responses from Alpha before they close the connection, without sacrificing performance? Is it possible somehow to read input from the socket after it was closed by the server?

回答1:

I have encountered the same problem as you. And I have tried two approaches, but none of them can reliably read the error responses from Apple before they close the connection :

  1. For each socket, I started two threads, one for writing continuously and the other for blocking read. In most cases, the read thread can read the error response when the write encounters "Socket Broken" exception, but it's not completely reliable.
  2. For each socket , I started only one thread to write continuously, and when encountered the exception, in the try cache block, try to read the error responses. In most cases, the socket is closed, so I read nothing but an exception.