@@ -25,14 +25,16 @@ type AppleNotificationServer struct {
25
25
logger * Logger
26
26
ApplePushSettings ApplePushSettings
27
27
sendTimeout time.Duration
28
+ retryTimeout time.Duration
28
29
}
29
30
30
- func NewAppleNotificationServer (settings ApplePushSettings , logger * Logger , metrics * metrics , sendTimeoutSecs int ) * AppleNotificationServer {
31
+ func NewAppleNotificationServer (settings ApplePushSettings , logger * Logger , metrics * metrics , sendTimeoutSecs int , retryTimeoutSecs int ) * AppleNotificationServer {
31
32
return & AppleNotificationServer {
32
33
ApplePushSettings : settings ,
33
34
metrics : metrics ,
34
35
logger : logger ,
35
36
sendTimeout : time .Duration (sendTimeoutSecs ) * time .Second ,
37
+ retryTimeout : time .Duration (retryTimeoutSecs ) * time .Second ,
36
38
}
37
39
}
38
40
@@ -227,15 +229,8 @@ func (me *AppleNotificationServer) SendNotification(msg *PushNotification) PushR
227
229
228
230
if me .AppleClient != nil {
229
231
me .logger .Infof ("Sending apple push notification for device=%v type=%v ackId=%v" , me .ApplePushSettings .Type , msg .Type , msg .AckID )
230
- start := time .Now ()
231
-
232
- ctx , cancel := context .WithTimeout (context .Background (), me .sendTimeout )
233
- defer cancel ()
234
232
235
- res , err := me .AppleClient .PushWithContext (ctx , notification )
236
- if me .metrics != nil {
237
- me .metrics .observerNotificationResponse (PushNotifyApple , time .Since (start ).Seconds ())
238
- }
233
+ res , err := me .SendNotificationWithRetry (notification )
239
234
if err != nil {
240
235
me .logger .Errorf ("Failed to send apple push sid=%v did=%v err=%v type=%v" , msg .ServerID , msg .DeviceID , err , me .ApplePushSettings .Type )
241
236
if me .metrics != nil {
@@ -269,3 +264,51 @@ func (me *AppleNotificationServer) SendNotification(msg *PushNotification) PushR
269
264
}
270
265
return NewOkPushResponse ()
271
266
}
267
+
268
+ func (me * AppleNotificationServer ) SendNotificationWithRetry (notification * apns.Notification ) (* apns.Response , error ) {
269
+ var res * apns.Response
270
+ var err error
271
+ waitTime := time .Second
272
+
273
+ // Keep a general context to make sure the whole retry
274
+ // doesn't take longer than the timeout.
275
+ generalContext , cancelGeneralContext := context .WithTimeout (context .Background (), me .sendTimeout )
276
+ defer cancelGeneralContext ()
277
+
278
+ for retries := 0 ; retries < MAX_RETRIES ; retries ++ {
279
+ start := time .Now ()
280
+
281
+ retryContext , cancelRetryContext := context .WithTimeout (generalContext , me .retryTimeout )
282
+ defer cancelRetryContext ()
283
+ res , err = me .AppleClient .PushWithContext (retryContext , notification )
284
+ if me .metrics != nil {
285
+ me .metrics .observerNotificationResponse (PushNotifyApple , time .Since (start ).Seconds ())
286
+ }
287
+
288
+ if err == nil {
289
+ break
290
+ }
291
+
292
+ me .logger .Errorf ("Failed to send apple push did=%v retry=%v error=%v" , notification .DeviceToken , retries , err )
293
+
294
+ if retries == MAX_RETRIES - 1 {
295
+ me .logger .Errorf ("Max retries reached did=%v" , notification .DeviceToken )
296
+ break
297
+ }
298
+
299
+ select {
300
+ case <- generalContext .Done ():
301
+ case <- time .After (waitTime ):
302
+ }
303
+
304
+ if generalContext .Err () != nil {
305
+ me .logger .Infof ("Not retrying because context error did=%v retry=%v error=%v" , notification .DeviceToken , retries , generalContext .Err ())
306
+ err = generalContext .Err ()
307
+ break
308
+ }
309
+
310
+ waitTime *= 2
311
+ }
312
+
313
+ return res , err
314
+ }
0 commit comments