chore: fix race condition with push iOS notification (#533)

This commit is contained in:
Bo-Yi Wu 2020-07-14 23:57:23 +08:00 committed by GitHub
parent 7c7e740fec
commit a4cc8d7582
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 18 additions and 36 deletions

View File

@ -360,7 +360,7 @@ func getApnsClient(req PushNotification) (client *apns2.Client) {
} }
// PushToIOS provide send notification to APNs server. // PushToIOS provide send notification to APNs server.
func PushToIOS(req PushNotification) bool { func PushToIOS(req PushNotification) {
LogAccess.Debug("Start push notification for iOS") LogAccess.Debug("Start push notification for iOS")
var ( var (
@ -374,7 +374,6 @@ func PushToIOS(req PushNotification) bool {
Retry: Retry:
var ( var (
isError = false
newTokens []string newTokens []string
) )
@ -386,12 +385,11 @@ Retry:
// occupy push slot // occupy push slot
MaxConcurrentIOSPushes <- struct{}{} MaxConcurrentIOSPushes <- struct{}{}
wg.Add(1) wg.Add(1)
go func(token string) { go func(notification apns2.Notification, token string) {
notification.DeviceToken = token notification.DeviceToken = token
// send ios notification // send ios notification
res, err := client.Push(notification) res, err := client.Push(&notification)
if err != nil || (res != nil && res.StatusCode != http.StatusOK) { if err != nil || (res != nil && res.StatusCode != http.StatusOK) {
if err == nil { if err == nil {
// error message: // error message:
@ -418,27 +416,24 @@ Retry:
if res != nil && res.StatusCode >= http.StatusInternalServerError { if res != nil && res.StatusCode >= http.StatusInternalServerError {
newTokens = append(newTokens, token) newTokens = append(newTokens, token)
} }
isError = true
} }
if res != nil && res.Sent() && !isError { if res != nil && res.Sent() {
LogPush(SucceededPush, token, req, nil) LogPush(SucceededPush, token, req, nil)
StatStorage.AddIosSuccess(1) StatStorage.AddIosSuccess(1)
} }
// free push slot // free push slot
<-MaxConcurrentIOSPushes <-MaxConcurrentIOSPushes
wg.Done() wg.Done()
}(token) }(*notification, token)
} }
wg.Wait() wg.Wait()
if isError && retryCount < maxRetry { if len(newTokens) > 0 && retryCount < maxRetry {
retryCount++ retryCount++
// resend fail token // resend fail token
req.Tokens = newTokens req.Tokens = newTokens
goto Retry goto Retry
} }
return isError
} }

View File

@ -706,14 +706,13 @@ func TestPushToIOS(t *testing.T) {
assert.Nil(t, err) assert.Nil(t, err)
req := PushNotification{ req := PushNotification{
Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7"}, Tokens: []string{"11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef7", "11aa01229f15f0f0c52029d8cf8cd0aeaf2365fe4cebc4af26cd6d76b7919ef1"},
Platform: 1, Platform: 1,
Message: "Welcome", Message: "Welcome",
} }
// send fail // send fail
isError := PushToIOS(req) PushToIOS(req)
assert.True(t, isError)
} }
func TestApnsHostFromRequest(t *testing.T) { func TestApnsHostFromRequest(t *testing.T) {

View File

@ -101,7 +101,7 @@ func GetAndroidNotification(req PushNotification) *fcm.Message {
} }
// PushToAndroid provide send notification to Android server. // PushToAndroid provide send notification to Android server.
func PushToAndroid(req PushNotification) bool { func PushToAndroid(req PushNotification) {
LogAccess.Debug("Start push notification for Android") LogAccess.Debug("Start push notification for Android")
var ( var (
@ -119,12 +119,10 @@ func PushToAndroid(req PushNotification) bool {
if err != nil { if err != nil {
LogError.Error("request error: " + err.Error()) LogError.Error("request error: " + err.Error())
return false return
} }
Retry: Retry:
var isError = false
notification := GetAndroidNotification(req) notification := GetAndroidNotification(req)
if req.APIKey != "" { if req.APIKey != "" {
@ -136,14 +134,14 @@ Retry:
if err != nil { if err != nil {
// FCM server error // FCM server error
LogError.Error("FCM server error: " + err.Error()) LogError.Error("FCM server error: " + err.Error())
return false return
} }
res, err := client.Send(notification) res, err := client.Send(notification)
if err != nil { if err != nil {
// Send Message error // Send Message error
LogError.Error("FCM server send message error: " + err.Error()) LogError.Error("FCM server send message error: " + err.Error())
return false return
} }
if !req.IsTopic() { if !req.IsTopic() {
@ -169,7 +167,6 @@ Retry:
if !result.Unregistered() { if !result.Unregistered() {
newTokens = append(newTokens, to) newTokens = append(newTokens, to)
} }
isError = true
LogPush(FailedPush, to, req, result.Error) LogPush(FailedPush, to, req, result.Error)
if PushConf.Core.Sync { if PushConf.Core.Sync {
@ -201,7 +198,6 @@ Retry:
if res.MessageID != 0 { if res.MessageID != 0 {
LogPush(SucceededPush, to, req, nil) LogPush(SucceededPush, to, req, nil)
} else { } else {
isError = true
// failure // failure
LogPush(FailedPush, to, req, res.Error) LogPush(FailedPush, to, req, res.Error)
if PushConf.Core.Sync { if PushConf.Core.Sync {
@ -212,7 +208,6 @@ Retry:
// Device Group HTTP Response // Device Group HTTP Response
if len(res.FailedRegistrationIDs) > 0 { if len(res.FailedRegistrationIDs) > 0 {
isError = true
newTokens = append(newTokens, res.FailedRegistrationIDs...) newTokens = append(newTokens, res.FailedRegistrationIDs...)
LogPush(FailedPush, notification.To, req, errors.New("device group: partial success or all fails")) LogPush(FailedPush, notification.To, req, errors.New("device group: partial success or all fails"))
@ -221,13 +216,11 @@ Retry:
} }
} }
if isError && retryCount < maxRetry { if len(newTokens) > 0 && retryCount < maxRetry {
retryCount++ retryCount++
// resend fail token // resend fail token
req.Tokens = newTokens req.Tokens = newTokens
goto Retry goto Retry
} }
return isError
} }

View File

@ -60,8 +60,7 @@ func TestPushToAndroidWrongToken(t *testing.T) {
} }
// Android Success count: 0, Failure count: 2 // Android Success count: 0, Failure count: 2
isError := PushToAndroid(req) PushToAndroid(req)
assert.True(t, isError)
} }
func TestPushToAndroidRightTokenForJSONLog(t *testing.T) { func TestPushToAndroidRightTokenForJSONLog(t *testing.T) {
@ -80,8 +79,7 @@ func TestPushToAndroidRightTokenForJSONLog(t *testing.T) {
Message: "Welcome", Message: "Welcome",
} }
isError := PushToAndroid(req) PushToAndroid(req)
assert.False(t, isError)
} }
func TestPushToAndroidRightTokenForStringLog(t *testing.T) { func TestPushToAndroidRightTokenForStringLog(t *testing.T) {
@ -98,8 +96,7 @@ func TestPushToAndroidRightTokenForStringLog(t *testing.T) {
Message: "Welcome", Message: "Welcome",
} }
isError := PushToAndroid(req) PushToAndroid(req)
assert.False(t, isError)
} }
func TestOverwriteAndroidAPIKey(t *testing.T) { func TestOverwriteAndroidAPIKey(t *testing.T) {
@ -119,8 +116,7 @@ func TestOverwriteAndroidAPIKey(t *testing.T) {
} }
// FCM server error: 401 error: 401 Unauthorized (Wrong API Key) // FCM server error: 401 error: 401 Unauthorized (Wrong API Key)
err := PushToAndroid(req) PushToAndroid(req)
assert.False(t, err)
} }
func TestFCMMessage(t *testing.T) { func TestFCMMessage(t *testing.T) {
@ -215,8 +211,7 @@ func TestCheckAndroidMessage(t *testing.T) {
TimeToLive: &timeToLive, TimeToLive: &timeToLive,
} }
err := PushToAndroid(req) PushToAndroid(req)
assert.False(t, err)
} }
func TestAndroidNotificationStructure(t *testing.T) { func TestAndroidNotificationStructure(t *testing.T) {