MM-27116: Drain push notification channel before closing (#15066)
* MM-27116: Drain push notification channel before closing Without this, pending push notifications will not be sent when shutting down or restarting the server. * Fix race * Re-arrange server shutdown Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
d05fd5327b
Коммит
c0fa478cdd
@@ -25,13 +25,16 @@ const (
|
|||||||
notificationTypeClear notificationType = "clear"
|
notificationTypeClear notificationType = "clear"
|
||||||
notificationTypeMessage notificationType = "message"
|
notificationTypeMessage notificationType = "message"
|
||||||
notificationTypeUpdateBadge notificationType = "update_badge"
|
notificationTypeUpdateBadge notificationType = "update_badge"
|
||||||
|
notificationTypeDummy notificationType = "dummy"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PushNotificationsHub struct {
|
type PushNotificationsHub struct {
|
||||||
notificationsChan chan PushNotification
|
notificationsChan chan PushNotification
|
||||||
app *App // XXX: This will go away once push notifications move to their own package.
|
app *App // XXX: This will go away once push notifications move to their own package.
|
||||||
sema chan struct{}
|
sema chan struct{}
|
||||||
|
stopChan chan struct{}
|
||||||
wg *sync.WaitGroup
|
wg *sync.WaitGroup
|
||||||
|
buffer int
|
||||||
}
|
}
|
||||||
|
|
||||||
type PushNotification struct {
|
type PushNotification struct {
|
||||||
@@ -256,54 +259,70 @@ func (s *Server) createPushNotificationsHub() {
|
|||||||
app: fakeApp,
|
app: fakeApp,
|
||||||
wg: new(sync.WaitGroup),
|
wg: new(sync.WaitGroup),
|
||||||
sema: make(chan struct{}, runtime.NumCPU()*8), // numCPU * 8 is a good amount of concurrency.
|
sema: make(chan struct{}, runtime.NumCPU()*8), // numCPU * 8 is a good amount of concurrency.
|
||||||
|
stopChan: make(chan struct{}),
|
||||||
|
buffer: buffer,
|
||||||
}
|
}
|
||||||
go hub.start()
|
go hub.start()
|
||||||
s.PushNotificationsHub = hub
|
s.PushNotificationsHub = hub
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hub *PushNotificationsHub) start() {
|
func (hub *PushNotificationsHub) start() {
|
||||||
for notification := range hub.notificationsChan {
|
for {
|
||||||
// Adding to the waitgroup first.
|
select {
|
||||||
hub.wg.Add(1)
|
case notification := <-hub.notificationsChan:
|
||||||
// Get token.
|
// Adding to the waitgroup first.
|
||||||
hub.sema <- struct{}{}
|
hub.wg.Add(1)
|
||||||
go func(notification PushNotification) {
|
// Get token.
|
||||||
defer func() {
|
hub.sema <- struct{}{}
|
||||||
// Release token.
|
go func(notification PushNotification) {
|
||||||
<-hub.sema
|
defer func() {
|
||||||
// Now marking waitgroup as done.
|
// Release token.
|
||||||
hub.wg.Done()
|
<-hub.sema
|
||||||
}()
|
// Now marking waitgroup as done.
|
||||||
|
hub.wg.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
var err *model.AppError
|
var err *model.AppError
|
||||||
switch notification.notificationType {
|
switch notification.notificationType {
|
||||||
case notificationTypeClear:
|
case notificationTypeClear:
|
||||||
err = hub.app.clearPushNotificationSync(notification.currentSessionId, notification.userId, notification.channelId)
|
err = hub.app.clearPushNotificationSync(notification.currentSessionId, notification.userId, notification.channelId)
|
||||||
case notificationTypeMessage:
|
case notificationTypeMessage:
|
||||||
err = hub.app.sendPushNotificationSync(
|
err = hub.app.sendPushNotificationSync(
|
||||||
notification.post,
|
notification.post,
|
||||||
notification.user,
|
notification.user,
|
||||||
notification.channel,
|
notification.channel,
|
||||||
notification.channelName,
|
notification.channelName,
|
||||||
notification.senderName,
|
notification.senderName,
|
||||||
notification.explicitMention,
|
notification.explicitMention,
|
||||||
notification.channelWideMention,
|
notification.channelWideMention,
|
||||||
notification.replyToThreadType,
|
notification.replyToThreadType,
|
||||||
)
|
)
|
||||||
case notificationTypeUpdateBadge:
|
case notificationTypeUpdateBadge:
|
||||||
err = hub.app.updateMobileAppBadgeSync(notification.userId)
|
err = hub.app.updateMobileAppBadgeSync(notification.userId)
|
||||||
default:
|
case notificationTypeDummy:
|
||||||
mlog.Error("Invalid notification type", mlog.String("notification_type", string(notification.notificationType)))
|
return
|
||||||
}
|
default:
|
||||||
|
mlog.Error("Invalid notification type", mlog.String("notification_type", string(notification.notificationType)))
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
mlog.Error("Unable to send push notification", mlog.String("notification_type", string(notification.notificationType)), mlog.Err(err))
|
mlog.Error("Unable to send push notification", mlog.String("notification_type", string(notification.notificationType)), mlog.Err(err))
|
||||||
}
|
}
|
||||||
}(notification)
|
}(notification)
|
||||||
|
case <-hub.stopChan:
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hub *PushNotificationsHub) stop() {
|
func (hub *PushNotificationsHub) stop() {
|
||||||
|
// Drain the channel.
|
||||||
|
for i := 0; i < hub.buffer+1; i++ {
|
||||||
|
hub.notificationsChan <- PushNotification{
|
||||||
|
notificationType: notificationTypeDummy,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hub.stopChan <- struct{}{}
|
||||||
close(hub.notificationsChan)
|
close(hub.notificationsChan)
|
||||||
hub.wg.Wait()
|
hub.wg.Wait()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -641,7 +641,6 @@ func (s *Server) Shutdown() error {
|
|||||||
defer sentry.Flush(2 * time.Second)
|
defer sentry.Flush(2 * time.Second)
|
||||||
|
|
||||||
s.HubStop()
|
s.HubStop()
|
||||||
s.StopPushNotificationsHubWorkers()
|
|
||||||
s.ShutDownPlugins()
|
s.ShutDownPlugins()
|
||||||
s.RemoveLicenseListener(s.licenseListenerId)
|
s.RemoveLicenseListener(s.licenseListenerId)
|
||||||
s.RemoveClusterLeaderChangedListener(s.clusterLeaderListenerId)
|
s.RemoveClusterLeaderChangedListener(s.clusterLeaderListenerId)
|
||||||
@@ -659,6 +658,8 @@ func (s *Server) Shutdown() error {
|
|||||||
|
|
||||||
s.StopHTTPServer()
|
s.StopHTTPServer()
|
||||||
s.stopLocalModeServer()
|
s.stopLocalModeServer()
|
||||||
|
// Push notification hub needs to be shutdown after HTTP server
|
||||||
|
s.StopPushNotificationsHubWorkers()
|
||||||
|
|
||||||
s.WaitForGoroutines()
|
s.WaitForGoroutines()
|
||||||
|
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user