MM-36545 Fix replica lag issue causing missed websocket events to update following (#17989)

* Fix replica lag issue causing missed websocket events to update following

* Add mutex to prevent data race

* Query thread membership if null

* Fix style
Этот коммит содержится в:
Joram Wilander
2021-07-26 11:28:01 -04:00
коммит произвёл GitHub
родитель e538604345
Коммит b01f8ab0c8

Просмотреть файл

@@ -8,6 +8,7 @@ import (
"net/http" "net/http"
"sort" "sort"
"strings" "strings"
"sync"
"unicode" "unicode"
"unicode/utf8" "unicode/utf8"
@@ -171,6 +172,8 @@ func (a *App) SendNotifications(post *model.Post, team *model.Team, channel *mod
updateMentionChans := []chan *model.AppError{} updateMentionChans := []chan *model.AppError{}
mentionAutofollowChans := []chan *model.AppError{} mentionAutofollowChans := []chan *model.AppError{}
threadParticipants := map[string]bool{post.UserId: true} threadParticipants := map[string]bool{post.UserId: true}
participantMemberships := map[string]*model.ThreadMembership{}
membershipsMutex := &sync.Mutex{}
if *a.Config().ServiceSettings.ThreadAutoFollow && post.RootId != "" { if *a.Config().ServiceSettings.ThreadAutoFollow && post.RootId != "" {
var rootMentions *ExplicitMentions var rootMentions *ExplicitMentions
if parentPostList != nil { if parentPostList != nil {
@@ -203,6 +206,9 @@ func (a *App) SendNotifications(post *model.Post, team *model.Team, channel *mod
} }
if membership != nil && !membership.Following { if membership != nil && !membership.Following {
membershipsMutex.Lock()
participantMemberships[userID] = membership
membershipsMutex.Unlock()
return return
} }
} }
@@ -217,11 +223,14 @@ func (a *App) SendNotifications(post *model.Post, team *model.Team, channel *mod
UpdateViewedTimestamp: userID == post.UserId, UpdateViewedTimestamp: userID == post.UserId,
UpdateParticipants: userID == post.UserId, UpdateParticipants: userID == post.UserId,
} }
_, err := a.Srv().Store.Thread().MaintainMembership(userID, post.RootId, opts) threadMembership, err := a.Srv().Store.Thread().MaintainMembership(userID, post.RootId, opts)
if err != nil { if err != nil {
mac <- model.NewAppError("SendNotifications", "app.channel.autofollow.app_error", nil, err.Error(), http.StatusInternalServerError) mac <- model.NewAppError("SendNotifications", "app.channel.autofollow.app_error", nil, err.Error(), http.StatusInternalServerError)
return return
} }
membershipsMutex.Lock()
participantMemberships[userID] = threadMembership
membershipsMutex.Unlock()
mac <- nil mac <- nil
}(id) }(id)
@@ -469,14 +478,20 @@ func (a *App) SendNotifications(post *model.Post, team *model.Team, channel *mod
for _, uid := range followers { for _, uid := range followers {
sendEvent := *a.Config().ServiceSettings.CollapsedThreads == model.CollapsedThreadsDefaultOn sendEvent := *a.Config().ServiceSettings.CollapsedThreads == model.CollapsedThreadsDefaultOn
// check if a participant has overridden collapsed threads settings // check if a participant has overridden collapsed threads settings
if preference, err := a.Srv().Store.Preference().Get(uid, model.PreferenceCategoryDisplaySettings, model.PreferenceNameCollapsedThreadsEnabled); err == nil { if preference, prefErr := a.Srv().Store.Preference().Get(uid, model.PreferenceCategoryDisplaySettings, model.PreferenceNameCollapsedThreadsEnabled); prefErr == nil {
sendEvent = preference.Value == "on" sendEvent = preference.Value == "on"
} }
if sendEvent { if sendEvent {
message := model.NewWebSocketEvent(model.WebsocketEventThreadUpdated, team.Id, "", uid, nil) message := model.NewWebSocketEvent(model.WebsocketEventThreadUpdated, team.Id, "", uid, nil)
threadMembership, err := a.Srv().Store.Thread().GetMembershipForUser(uid, post.RootId) threadMembership := participantMemberships[uid]
if err != nil { if threadMembership == nil {
return nil, errors.Wrapf(err, "cannot get thread membership %q for user %q", post.RootId, uid) threadMembership, err = a.Srv().Store.Thread().GetMembershipForUser(uid, post.RootId)
if err != nil {
return nil, errors.Wrapf(err, "Missing thread membership for participant in notifications. user_id=%q thread_id=%q", uid, post.RootId)
}
if threadMembership == nil {
continue
}
} }
userThread, err := a.Srv().Store.Thread().GetThreadForUser(channel.TeamId, threadMembership, true) userThread, err := a.Srv().Store.Thread().GetThreadForUser(channel.TeamId, threadMembership, true)
if err != nil { if err != nil {