From 4eabf5ba31a899be32ebd65bd4c8467d1d0ef979 Mon Sep 17 00:00:00 2001 From: "anton.buksa" Date: Wed, 13 Nov 2024 10:48:43 +0100 Subject: [PATCH 1/4] delay ws channel resubs on reconnect until post prefetch finished Changelog: changed --- webapp/channels/src/actions/views/channel.ts | 1 + .../src/actions/websocket_actions.jsx | 7 ++ .../data_prefetch/data_prefetch.tsx | 19 ++++- webapp/platform/client/src/websocket.ts | 75 +++++++++++++++---- 4 files changed, 85 insertions(+), 17 deletions(-) diff --git a/webapp/channels/src/actions/views/channel.ts b/webapp/channels/src/actions/views/channel.ts index 48409e3d39..f38dc7c49f 100644 --- a/webapp/channels/src/actions/views/channel.ts +++ b/webapp/channels/src/actions/views/channel.ts @@ -448,6 +448,7 @@ export function syncPostsInChannel(channelId: string, since: number, prefetch = status: RequestStatus.FAILURE, }); } else { + console.log('PREFETCH_POSTS_FOR_CHANNEL', channelId, 'RequestStatus.SUCCESS', Date.now()); actions.push({ type: ActionTypes.PREFETCH_POSTS_FOR_CHANNEL, channelId, diff --git a/webapp/channels/src/actions/websocket_actions.jsx b/webapp/channels/src/actions/websocket_actions.jsx index 59677a8e8f..c1dc07c163 100644 --- a/webapp/channels/src/actions/websocket_actions.jsx +++ b/webapp/channels/src/actions/websocket_actions.jsx @@ -243,6 +243,13 @@ function restart() { dispatch(getClientConfig()); } +export function reconnectWsChannels() { + console.log('[websocket_actions] reconnectWsChannels - WebSocketClient.reconnecting', WebSocketClient.reconnecting); + if (WebSocketClient.reconnecting) { + WebSocketClient.reconnectAllChannels(); + } +} + export async function reconnect(socketId) { // eslint-disable-next-line console.log('Reconnecting WebSocket'); diff --git a/webapp/channels/src/components/data_prefetch/data_prefetch.tsx b/webapp/channels/src/components/data_prefetch/data_prefetch.tsx index 90134b8156..5c53d7ad4c 100644 --- a/webapp/channels/src/components/data_prefetch/data_prefetch.tsx +++ b/webapp/channels/src/components/data_prefetch/data_prefetch.tsx @@ -9,6 +9,7 @@ import type {Channel} from '@mattermost/types/channels'; import type {ActionResult} from 'mattermost-redux/types/actions'; import {loadProfilesForSidebar} from 'actions/user_actions'; +import {reconnectWsChannels} from 'actions/websocket_actions'; import {Constants} from 'utils/constants'; @@ -54,7 +55,7 @@ export default class DataPrefetch extends React.PureComponent { private prefetchTimeout?: number; async componentDidUpdate(prevProps: Props) { - const {currentChannelId, prefetchQueueObj, sidebarLoaded} = this.props; + const {currentChannelId, prefetchQueueObj, sidebarLoaded, prefetchRequestStatus} = this.props; if (currentChannelId && sidebarLoaded && (!prevProps.currentChannelId || !prevProps.sidebarLoaded)) { queue.add(async () => this.prefetchPosts(currentChannelId)); await loadProfilesForSidebar(); @@ -65,6 +66,21 @@ export default class DataPrefetch extends React.PureComponent { this.prefetchData(); } + console.log(prefetchQueueObj); + console.log(prefetchRequestStatus); + + // Infomaniak: if websocket is connecting at the same time this will delay channel subscriptions until all channels have finished prefetch + if (prevProps.prefetchQueueObj !== prefetchQueueObj || prevProps.prefetchRequestStatus !== prefetchRequestStatus) { + const queueCount = Object.values(prefetchQueueObj).map((x) => x.length).reduce((accumulator, currentValue) => accumulator + currentValue, 0); + const statusCount = Object.keys(prefetchRequestStatus).length; + const allStatusSuccessful = !(Object.values(prefetchRequestStatus).some((x) => x !== 'success')) + + if (queueCount === statusCount && allStatusSuccessful) { + console.log('prefetch complete'); + reconnectWsChannels(); + } + } + if (currentChannelId && sidebarLoaded && (!prevProps.currentChannelId || !prevProps.sidebarLoaded)) { this.props.actions.trackPreloadedChannels(prefetchQueueObj); } @@ -96,6 +112,7 @@ export default class DataPrefetch extends React.PureComponent { } } } + console.log('prefetchRequestStatus', prefetchRequestStatus); }; render() { diff --git a/webapp/platform/client/src/websocket.ts b/webapp/platform/client/src/websocket.ts index 6bc7e9f4bc..d6f9267ee3 100644 --- a/webapp/platform/client/src/websocket.ts +++ b/webapp/platform/client/src/websocket.ts @@ -93,6 +93,16 @@ export default class WebSocketClient { private connectionId: string | null; + private _teamId: string | undefined; + private _userId: number | undefined; + private _userTeamId: string | undefined; + // TODO type this + private _currentUserId: any; + private _currentUserTeamId: any; + private _presenceChannelId: any; + + reconnecting: boolean = false; + constructor() { this.conn = null; this.teamChannel = null; @@ -111,8 +121,15 @@ export default class WebSocketClient { this.currentUser = null; this.currentTeamUser = ''; this.currentTeam = ''; - this.otherTeams = [] - this.otherTeamsChannel = {} + this.otherTeams = []; + this.otherTeamsChannel = {}; + + this._teamId = undefined; + this._userId = undefined; + this._currentUserId = undefined; + this._userTeamId = undefined; + this._currentUserTeamId = undefined; + this._presenceChannelId = undefined; } unbindPusherEvents() { @@ -236,35 +253,61 @@ export default class WebSocketClient { }); this.conn.connection.bind('connected', () => { - this.subscribeToTeamChannel(teamId as string); - this.subscribeToUserChannel(userId || currentUserId); - this.subscribeToUserTeamScopedChannel(userTeamId || currentUserTeamId); - this.subscribeToOtherTeams(this.otherTeams, teamId) - - // There is a case where presenceChannelId can be undefined on first connect and will be set by the bind function later. - const presenceChannel = presenceChannelId || this.currentPresence; - if (presenceChannel) { - this.bindPresenceChannel(presenceChannel); - } + console.log('[websocket] socketId', this.conn?.connection.socket_id); + + // TODO: temp bind just to keep consistence with old code + this._teamId = teamId; + this._userId = userId; + this._currentUserId = currentUserId; + this._userTeamId = userTeamId; + this._currentUserTeamId = currentUserTeamId; + this._presenceChannelId = presenceChannelId; - console.log('[websocket] re-established connection'); if (this.connectFailCount > 0) { console.log('[websocket] calling reconnect callbacks'); - console.log('[websocket] socketId', this.conn?.connection.socket_id); + // used by websocket_actions to determine whether to call reconnectAllChannels after preload + this.reconnecting = true; + console.log('[websocket] reconnecting'); this.reconnectCallback?.(this.conn?.connection.socket_id); this.reconnectListeners.forEach((listener) => listener(this.conn?.connection.socket_id)); - } else if (this.firstConnectCallback || this.firstConnectListeners.size > 0) { + } else { + // if first connect manually call reconnectAllChannels + this.reconnectAllChannels(); console.log('[websocket] calling first connect callbacks'); - console.log('[websocket] socketId', this.conn?.connection.socket_id); this.firstConnectCallback?.(this.conn?.connection.socket_id); this.firstConnectListeners.forEach((listener) => listener(this.conn?.connection.socket_id)); } + this.connectFailCount = 0; this.errorCount = 0; this.socketId = this.conn?.connection.socket_id as string; }); } + reconnectAllChannels() { + console.log('[websocket] reconnectAllChannels state', this.conn?.connection.state) + if (this.conn?.connection.state !== 'connected') { + console.log('[websocket] reconnectAllChannels retrying'); + setTimeout(() => { + this.reconnectAllChannels(); + }, 2000); + + return; + } + this.subscribeToTeamChannel(this._teamId as string); + this.subscribeToUserChannel(this._userId || this._currentUserId); + this.subscribeToUserTeamScopedChannel(this._userTeamId || this._currentUserTeamId); + this.subscribeToOtherTeams(this.otherTeams, this._teamId); + + const presenceChannel = this._presenceChannelId || this.currentPresence; + if (presenceChannel) { + this.bindPresenceChannel(presenceChannel); + } + + this.reconnecting = false; + console.log('[websocket] connected at', Date.now()); + } + updateToken(token: string) { if (this.conn) { this.conn.disconnect(); From b0c0aa8d672696c10d7a0b752d15141924f84eab Mon Sep 17 00:00:00 2001 From: "anton.buksa" Date: Wed, 13 Nov 2024 15:01:59 +0100 Subject: [PATCH 2/4] clean --- webapp/channels/src/actions/views/channel.ts | 2 ++ webapp/channels/src/actions/websocket_actions.jsx | 1 - .../channels/src/components/data_prefetch/data_prefetch.tsx | 6 ++---- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/webapp/channels/src/actions/views/channel.ts b/webapp/channels/src/actions/views/channel.ts index f38dc7c49f..cbbe2e9949 100644 --- a/webapp/channels/src/actions/views/channel.ts +++ b/webapp/channels/src/actions/views/channel.ts @@ -423,6 +423,8 @@ export function syncPostsInChannel(channelId: string, since: number, prefetch = sinceTimeToGetPosts = lastPostsApiCallForChannel; } + console.log('sinceTimeToGetPosts', channelId, sinceTimeToGetPosts, 'prefetch', prefetch); + if (prefetch) { dispatch({ type: ActionTypes.PREFETCH_POSTS_FOR_CHANNEL, diff --git a/webapp/channels/src/actions/websocket_actions.jsx b/webapp/channels/src/actions/websocket_actions.jsx index c1dc07c163..e49b89f974 100644 --- a/webapp/channels/src/actions/websocket_actions.jsx +++ b/webapp/channels/src/actions/websocket_actions.jsx @@ -345,7 +345,6 @@ export async function reconnect(socketId) { // eslint-disable-next-line no-console dispatch(checkForModifiedUsers(true)); dispatch(TeamActions.getMyKSuites()); - console.log('[websocket_actions] lastDisconnectAt: ', state.websocket.lastDisconnectAt); } dispatch(resetWsErrorCount()); diff --git a/webapp/channels/src/components/data_prefetch/data_prefetch.tsx b/webapp/channels/src/components/data_prefetch/data_prefetch.tsx index 5c53d7ad4c..dc13c03432 100644 --- a/webapp/channels/src/components/data_prefetch/data_prefetch.tsx +++ b/webapp/channels/src/components/data_prefetch/data_prefetch.tsx @@ -66,14 +66,13 @@ export default class DataPrefetch extends React.PureComponent { this.prefetchData(); } - console.log(prefetchQueueObj); - console.log(prefetchRequestStatus); + // console.log('prefetchQueueObj', prefetchQueueObj); // Infomaniak: if websocket is connecting at the same time this will delay channel subscriptions until all channels have finished prefetch if (prevProps.prefetchQueueObj !== prefetchQueueObj || prevProps.prefetchRequestStatus !== prefetchRequestStatus) { const queueCount = Object.values(prefetchQueueObj).map((x) => x.length).reduce((accumulator, currentValue) => accumulator + currentValue, 0); const statusCount = Object.keys(prefetchRequestStatus).length; - const allStatusSuccessful = !(Object.values(prefetchRequestStatus).some((x) => x !== 'success')) + const allStatusSuccessful = !(Object.values(prefetchRequestStatus).some((x) => x !== 'success')); if (queueCount === statusCount && allStatusSuccessful) { console.log('prefetch complete'); @@ -112,7 +111,6 @@ export default class DataPrefetch extends React.PureComponent { } } } - console.log('prefetchRequestStatus', prefetchRequestStatus); }; render() { From b12d0789dec47f88965b1d2c776b3142dfdfc049 Mon Sep 17 00:00:00 2001 From: "anton.buksa" Date: Wed, 13 Nov 2024 15:12:22 +0100 Subject: [PATCH 3/4] restore condition --- webapp/platform/client/src/websocket.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/platform/client/src/websocket.ts b/webapp/platform/client/src/websocket.ts index d6f9267ee3..a76ce79b77 100644 --- a/webapp/platform/client/src/websocket.ts +++ b/webapp/platform/client/src/websocket.ts @@ -270,7 +270,7 @@ export default class WebSocketClient { console.log('[websocket] reconnecting'); this.reconnectCallback?.(this.conn?.connection.socket_id); this.reconnectListeners.forEach((listener) => listener(this.conn?.connection.socket_id)); - } else { + } else if (this.firstConnectCallback || this.firstConnectListeners.size > 0) { // if first connect manually call reconnectAllChannels this.reconnectAllChannels(); console.log('[websocket] calling first connect callbacks'); From 7e0dbacd2dd7fc8bdc91fdc018ca13996b90f2c3 Mon Sep 17 00:00:00 2001 From: "anton.buksa" Date: Wed, 13 Nov 2024 15:21:32 +0100 Subject: [PATCH 4/4] update snapshots --- ...post_body_additional_content.test.tsx.snap | 14 ++++++++++ .../__snapshots__/pluggable.test.tsx.snap | 28 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/webapp/channels/src/components/post_view/post_body_additional_content/__snapshots__/post_body_additional_content.test.tsx.snap b/webapp/channels/src/components/post_view/post_body_additional_content/__snapshots__/post_body_additional_content.test.tsx.snap index d5e38c9159..42c85b6599 100644 --- a/webapp/channels/src/components/post_view/post_body_additional_content/__snapshots__/post_body_additional_content.test.tsx.snap +++ b/webapp/channels/src/components/post_view/post_body_additional_content/__snapshots__/post_body_additional_content.test.tsx.snap @@ -97,6 +97,12 @@ exports[`PostBodyAdditionalContent with a normal link Should render the plugin c } webSocketClient={ WebSocketClient { + "_currentUserId": undefined, + "_currentUserTeamId": undefined, + "_presenceChannelId": undefined, + "_teamId": undefined, + "_userId": undefined, + "_userTeamId": undefined, "closeCallback": null, "closeListeners": Set {}, "conn": null, @@ -122,6 +128,7 @@ exports[`PostBodyAdditionalContent with a normal link Should render the plugin c "presenceChannel": null, "reconnectCallback": null, "reconnectListeners": Set {}, + "reconnecting": false, "responseCallbacks": Object {}, "responseSequence": 1, "serverSequence": 0, @@ -156,6 +163,12 @@ exports[`PostBodyAdditionalContent with a normal link Should render the plugin c } webSocketClient={ WebSocketClient { + "_currentUserId": undefined, + "_currentUserTeamId": undefined, + "_presenceChannelId": undefined, + "_teamId": undefined, + "_userId": undefined, + "_userTeamId": undefined, "closeCallback": null, "closeListeners": Set {}, "conn": null, @@ -181,6 +194,7 @@ exports[`PostBodyAdditionalContent with a normal link Should render the plugin c "presenceChannel": null, "reconnectCallback": null, "reconnectListeners": Set {}, + "reconnecting": false, "responseCallbacks": Object {}, "responseSequence": 1, "serverSequence": 0, diff --git a/webapp/channels/src/plugins/pluggable/__snapshots__/pluggable.test.tsx.snap b/webapp/channels/src/plugins/pluggable/__snapshots__/pluggable.test.tsx.snap index b49b96f31f..771d117a0b 100644 --- a/webapp/channels/src/plugins/pluggable/__snapshots__/pluggable.test.tsx.snap +++ b/webapp/channels/src/plugins/pluggable/__snapshots__/pluggable.test.tsx.snap @@ -41,6 +41,12 @@ exports[`plugins/Pluggable should match snapshot with extended component 1`] = `