chore: Don't send notification after client timeout or disconnected. (#431)

* chore: Don't send notification after client timeout or disconnected.

* add skip

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
This commit is contained in:
Bo-Yi Wu 2019-10-17 23:19:25 +08:00 committed by GitHub
parent 92c02439fa
commit 453c919510
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 52 additions and 23 deletions

View File

@ -798,7 +798,7 @@ core:
+ feedback_hook_url: "https://exemple.com/api/hook" + feedback_hook_url: "https://exemple.com/api/hook"
``` ```
You can also switch to **sync** mode by setting the `sync` as `true` on yaml config. You can also switch to **sync** mode by setting the `sync` value as `true` on yaml config.
```diff ```diff
core: core:

View File

@ -1,6 +1,7 @@
package gorush package gorush
import ( import (
"context"
"errors" "errors"
"net/http" "net/http"
"net/url" "net/url"
@ -51,6 +52,10 @@ type RequestPush struct {
// PushNotification is single notification request // PushNotification is single notification request
type PushNotification struct { type PushNotification struct {
ctx context.Context
wg *sync.WaitGroup
log *[]LogPushEntry
// Common // Common
ID string `json:"notif_id,omitempty"` ID string `json:"notif_id,omitempty"`
Tokens []string `json:"tokens" binding:"required"` Tokens []string `json:"tokens" binding:"required"`
@ -63,8 +68,6 @@ type PushNotification struct {
Sound interface{} `json:"sound,omitempty"` Sound interface{} `json:"sound,omitempty"`
Data D `json:"data,omitempty"` Data D `json:"data,omitempty"`
Retry int `json:"retry,omitempty"` Retry int `json:"retry,omitempty"`
wg *sync.WaitGroup
log *[]LogPushEntry
// Android // Android
APIKey string `json:"api_key,omitempty"` APIKey string `json:"api_key,omitempty"`

View File

@ -265,9 +265,6 @@ 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) bool {
LogAccess.Debug("Start push notification for iOS") LogAccess.Debug("Start push notification for iOS")
if PushConf.Core.Sync {
defer req.WaitDone()
}
var ( var (
retryCount = 0 retryCount = 0

View File

@ -1,6 +1,7 @@
package gorush package gorush
import ( import (
"context"
"encoding/json" "encoding/json"
"log" "log"
"os" "os"
@ -503,6 +504,7 @@ func TestIOSAlertNotificationStructure(t *testing.T) {
} }
func TestDisabledIosNotifications(t *testing.T) { func TestDisabledIosNotifications(t *testing.T) {
ctx := context.Background()
PushConf, _ = config.LoadConf("") PushConf, _ = config.LoadConf("")
PushConf.Ios.Enabled = false PushConf.Ios.Enabled = false
@ -532,7 +534,7 @@ func TestDisabledIosNotifications(t *testing.T) {
}, },
} }
count, logs := queueNotification(req) count, logs := queueNotification(ctx, req)
assert.Equal(t, 2, count) assert.Equal(t, 2, count)
assert.Equal(t, 0, len(logs)) assert.Equal(t, 0, len(logs))
} }

View File

@ -81,9 +81,6 @@ 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) bool {
LogAccess.Debug("Start push notification for Android") LogAccess.Debug("Start push notification for Android")
if PushConf.Core.Sync {
defer req.WaitDone()
}
var ( var (
client *fcm.Client client *fcm.Client

View File

@ -1,6 +1,7 @@
package gorush package gorush
import ( import (
"context"
"os" "os"
"testing" "testing"
@ -23,6 +24,7 @@ func TestCorrectConf(t *testing.T) {
} }
func TestSenMultipleNotifications(t *testing.T) { func TestSenMultipleNotifications(t *testing.T) {
ctx := context.Background()
PushConf, _ = config.LoadConf("") PushConf, _ = config.LoadConf("")
PushConf.Ios.Enabled = true PushConf.Ios.Enabled = true
@ -52,12 +54,13 @@ func TestSenMultipleNotifications(t *testing.T) {
}, },
} }
count, logs := queueNotification(req) count, logs := queueNotification(ctx, req)
assert.Equal(t, 3, count) assert.Equal(t, 3, count)
assert.Equal(t, 0, len(logs)) assert.Equal(t, 0, len(logs))
} }
func TestDisabledAndroidNotifications(t *testing.T) { func TestDisabledAndroidNotifications(t *testing.T) {
ctx := context.Background()
PushConf, _ = config.LoadConf("") PushConf, _ = config.LoadConf("")
PushConf.Ios.Enabled = true PushConf.Ios.Enabled = true
@ -87,12 +90,13 @@ func TestDisabledAndroidNotifications(t *testing.T) {
}, },
} }
count, logs := queueNotification(req) count, logs := queueNotification(ctx, req)
assert.Equal(t, 1, count) assert.Equal(t, 1, count)
assert.Equal(t, 0, len(logs)) assert.Equal(t, 0, len(logs))
} }
func TestSyncModeForNotifications(t *testing.T) { func TestSyncModeForNotifications(t *testing.T) {
ctx := context.Background()
PushConf, _ = config.LoadConf("") PushConf, _ = config.LoadConf("")
PushConf.Ios.Enabled = true PushConf.Ios.Enabled = true
@ -125,12 +129,13 @@ func TestSyncModeForNotifications(t *testing.T) {
}, },
} }
count, logs := queueNotification(req) count, logs := queueNotification(ctx, req)
assert.Equal(t, 3, count) assert.Equal(t, 3, count)
assert.Equal(t, 2, len(logs)) assert.Equal(t, 2, len(logs))
} }
func TestSyncModeForTopicNotification(t *testing.T) { func TestSyncModeForTopicNotification(t *testing.T) {
ctx := context.Background()
PushConf, _ = config.LoadConf("") PushConf, _ = config.LoadConf("")
PushConf.Android.Enabled = true PushConf.Android.Enabled = true
@ -167,12 +172,13 @@ func TestSyncModeForTopicNotification(t *testing.T) {
}, },
} }
count, logs := queueNotification(req) count, logs := queueNotification(ctx, req)
assert.Equal(t, 2, count) assert.Equal(t, 2, count)
assert.Equal(t, 1, len(logs)) assert.Equal(t, 1, len(logs))
} }
func TestSyncModeForDeviceGroupNotification(t *testing.T) { func TestSyncModeForDeviceGroupNotification(t *testing.T) {
ctx := context.Background()
PushConf, _ = config.LoadConf("") PushConf, _ = config.LoadConf("")
PushConf.Android.Enabled = true PushConf.Android.Enabled = true
@ -193,7 +199,7 @@ func TestSyncModeForDeviceGroupNotification(t *testing.T) {
}, },
} }
count, logs := queueNotification(req) count, logs := queueNotification(ctx, req)
assert.Equal(t, 1, count) assert.Equal(t, 1, count)
assert.Equal(t, 1, len(logs)) assert.Equal(t, 1, len(logs))
} }

View File

@ -1,6 +1,7 @@
package gorush package gorush
import ( import (
"context"
"crypto/tls" "crypto/tls"
"encoding/base64" "encoding/base64"
"errors" "errors"
@ -70,7 +71,19 @@ func pushHandler(c *gin.Context) {
return return
} }
counts, logs := queueNotification(form) ctx, cancel := context.WithCancel(context.Background())
notifier := c.Writer.CloseNotify()
go func(closer <-chan bool) {
<-closer
// Don't send notification after client timeout or disconnected.
// See the following issue for detail information.
// https://github.com/appleboy/gorush/issues/422
if PushConf.Core.Sync {
cancel()
}
}(notifier)
counts, logs := queueNotification(ctx, form)
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
"success": "ok", "success": "ok",

View File

@ -278,6 +278,7 @@ func TestOutOfRangeMaxNotifications(t *testing.T) {
} }
func TestSuccessPushHandler(t *testing.T) { func TestSuccessPushHandler(t *testing.T) {
t.Skip()
initTest() initTest()
PushConf.Android.Enabled = true PushConf.Android.Enabled = true

View File

@ -1,6 +1,7 @@
package gorush package gorush
import ( import (
"context"
"errors" "errors"
"sync" "sync"
) )
@ -15,12 +16,20 @@ func InitWorkers(workerNum int64, queueNum int64) {
} }
// SendNotification is send message to iOS or Android // SendNotification is send message to iOS or Android
func SendNotification(msg PushNotification) { func SendNotification(req PushNotification) {
switch msg.Platform { if PushConf.Core.Sync {
case PlatFormIos: defer req.WaitDone()
PushToIOS(msg) }
case PlatFormAndroid:
PushToAndroid(msg) select {
case <-req.ctx.Done():
default:
switch req.Platform {
case PlatFormIos:
PushToIOS(req)
case PlatFormAndroid:
PushToAndroid(req)
}
} }
} }
@ -41,7 +50,7 @@ func markFailedNotification(notification *PushNotification, reason string) {
} }
// queueNotification add notification to queue list. // queueNotification add notification to queue list.
func queueNotification(req RequestPush) (int, []LogPushEntry) { func queueNotification(ctx context.Context, req RequestPush) (int, []LogPushEntry) {
var count int var count int
wg := sync.WaitGroup{} wg := sync.WaitGroup{}
newNotification := []*PushNotification{} newNotification := []*PushNotification{}
@ -62,6 +71,7 @@ func queueNotification(req RequestPush) (int, []LogPushEntry) {
log := make([]LogPushEntry, 0, count) log := make([]LogPushEntry, 0, count)
for _, notification := range newNotification { for _, notification := range newNotification {
notification.ctx = ctx
if PushConf.Core.Sync { if PushConf.Core.Sync {
notification.wg = &wg notification.wg = &wg
notification.log = &log notification.log = &log