MM-56906: Remove redundant calls on team switch (#30771)
On page load, we load ALL channels and channel members from all teams. But then, on team_switch, we would again load channels and channel members from that team. This was redundant and mainly kept because previously the websocket events were considered unreliable. Now with reliable websockets, and client-side pings, we can detect broken connections faster and recover without loss. Additionally, the getAllChannelMembers call would page through all responses on the client side. This was inefficient and incur extra latency. To optimize for this, we introduce server-side streaming of the full response if page is set to -1. This optimizes the intial response as well. https://mattermost.atlassian.net/browse/MM-56906 ```release-note Optimize team switch operation by removing calls to get channels and channel members. ``` Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
883711c72d
Коммит
4803892492
@@ -3094,14 +3094,62 @@ func getChannelMembersForUser(c *Context, w http.ResponseWriter, r *http.Request
|
||||
return
|
||||
}
|
||||
|
||||
members, err := c.App.GetChannelMembersWithTeamDataForUserWithPagination(c.AppContext, c.Params.UserId, c.Params.Page, c.Params.PerPage)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
// For backward compatibility purposes
|
||||
if c.Params.Page != -1 {
|
||||
cursor := &model.ChannelMemberCursor{
|
||||
Page: c.Params.Page,
|
||||
PerPage: c.Params.PerPage,
|
||||
}
|
||||
members, err := c.App.GetChannelMembersWithTeamDataForUserWithPagination(c.AppContext, c.Params.UserId, cursor)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
if err := json.NewEncoder(w).Encode(members); err != nil {
|
||||
c.Logger.Warn("Error while writing response", mlog.Err(err))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err := json.NewEncoder(w).Encode(members); err != nil {
|
||||
c.Logger.Warn("Error while writing response", mlog.Err(err))
|
||||
// The new model streams data using NDJSON format (each JSON object on a new line)
|
||||
pageSize := 100
|
||||
fromChannelID := ""
|
||||
|
||||
// Set the correct content type for NDJSON
|
||||
w.Header().Set("Content-Type", "application/x-ndjson")
|
||||
|
||||
enc := json.NewEncoder(w)
|
||||
|
||||
for {
|
||||
cursor := &model.ChannelMemberCursor{
|
||||
Page: -1,
|
||||
PerPage: pageSize,
|
||||
FromChannelID: fromChannelID,
|
||||
}
|
||||
|
||||
members, err := c.App.GetChannelMembersWithTeamDataForUserWithPagination(c.AppContext, c.Params.UserId, cursor)
|
||||
if err != nil {
|
||||
// If the page size was a perfect multiple of the total number of results,
|
||||
// then the last query will always return zero results.
|
||||
if fromChannelID != "" && err.Id == app.MissingChannelMemberError {
|
||||
break
|
||||
}
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
for _, member := range members {
|
||||
if err := enc.Encode(member); err != nil {
|
||||
c.Logger.Warn("Error while writing response", mlog.Err(err))
|
||||
}
|
||||
}
|
||||
|
||||
if len(members) < pageSize {
|
||||
break
|
||||
}
|
||||
|
||||
fromChannelID = members[len(members)-1].ChannelId
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6664,6 +6664,24 @@ func TestGetChannelMembersWithTeamData(t *testing.T) {
|
||||
for _, ch := range channels {
|
||||
assert.Equal(t, th.BasicTeam.DisplayName, ch.TeamDisplayName)
|
||||
}
|
||||
|
||||
channels, resp, err = th.Client.GetChannelMembersWithTeamData(context.Background(), th.BasicUser.Id, 0, 5000)
|
||||
require.NoError(t, err)
|
||||
CheckOKStatus(t, resp)
|
||||
assert.Len(t, channels, 6)
|
||||
for _, ch := range channels {
|
||||
assert.Equal(t, th.BasicTeam.DisplayName, ch.TeamDisplayName)
|
||||
}
|
||||
|
||||
// perPage doesn't matter if page=-1
|
||||
channels, resp, err = th.Client.GetChannelMembersWithTeamData(context.Background(), th.BasicUser.Id, -1, 2)
|
||||
require.NoError(t, err)
|
||||
CheckOKStatus(t, resp)
|
||||
assert.Equal(t, "application/x-ndjson", resp.Header.Get("Content-Type"))
|
||||
assert.Len(t, channels, 6)
|
||||
for _, ch := range channels {
|
||||
assert.Equal(t, th.BasicTeam.DisplayName, ch.TeamDisplayName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMigrateAuthToLDAP(t *testing.T) {
|
||||
|
||||
Ссылка в новой задаче
Block a user