Skip to content

Commit

Permalink
Merge branch 'rm/370678_2' into 'master'
Browse files Browse the repository at this point in the history
delay ws channel resubs on reconnect until post prefetch finished

See merge request kchat/webapp!965
  • Loading branch information
antonbuks committed Nov 13, 2024
2 parents 90825c6 + 7e0dbac commit ab8499a
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 17 deletions.
3 changes: 3 additions & 0 deletions webapp/channels/src/actions/views/channel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -448,6 +450,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,
Expand Down
8 changes: 7 additions & 1 deletion webapp/channels/src/actions/websocket_actions.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -338,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());
Expand Down
17 changes: 16 additions & 1 deletion webapp/channels/src/components/data_prefetch/data_prefetch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -54,7 +55,7 @@ export default class DataPrefetch extends React.PureComponent<Props> {
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();
Expand All @@ -65,6 +66,20 @@ export default class DataPrefetch extends React.PureComponent<Props> {
this.prefetchData();
}

// 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'));

if (queueCount === statusCount && allStatusSuccessful) {
console.log('prefetch complete');
reconnectWsChannels();
}
}

if (currentChannelId && sidebarLoaded && (!prevProps.currentChannelId || !prevProps.sidebarLoaded)) {
this.props.actions.trackPreloadedChannels(prefetchQueueObj);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ exports[`plugins/Pluggable should match snapshot with extended component 1`] = `
<ProfilePopoverPlugin
webSocketClient={
WebSocketClient {
"_currentUserId": undefined,
"_currentUserTeamId": undefined,
"_presenceChannelId": undefined,
"_teamId": undefined,
"_userId": undefined,
"_userTeamId": undefined,
"closeCallback": null,
"closeListeners": Set {},
"conn": null,
Expand All @@ -66,6 +72,7 @@ exports[`plugins/Pluggable should match snapshot with extended component 1`] = `
"presenceChannel": null,
"reconnectCallback": null,
"reconnectListeners": Set {},
"reconnecting": false,
"responseCallbacks": Object {},
"responseSequence": 1,
"serverSequence": 0,
Expand Down Expand Up @@ -127,6 +134,12 @@ exports[`plugins/Pluggable should match snapshot with extended component with pl
<ProfilePopoverPlugin
webSocketClient={
WebSocketClient {
"_currentUserId": undefined,
"_currentUserTeamId": undefined,
"_presenceChannelId": undefined,
"_teamId": undefined,
"_userId": undefined,
"_userTeamId": undefined,
"closeCallback": null,
"closeListeners": Set {},
"conn": null,
Expand All @@ -152,6 +165,7 @@ exports[`plugins/Pluggable should match snapshot with extended component with pl
"presenceChannel": null,
"reconnectCallback": null,
"reconnectListeners": Set {},
"reconnecting": false,
"responseCallbacks": Object {},
"responseSequence": 1,
"serverSequence": 0,
Expand Down Expand Up @@ -279,6 +293,12 @@ exports[`plugins/Pluggable should match snapshot with null pluggableId 1`] = `
<ProfilePopoverPlugin
webSocketClient={
WebSocketClient {
"_currentUserId": undefined,
"_currentUserTeamId": undefined,
"_presenceChannelId": undefined,
"_teamId": undefined,
"_userId": undefined,
"_userTeamId": undefined,
"closeCallback": null,
"closeListeners": Set {},
"conn": null,
Expand All @@ -304,6 +324,7 @@ exports[`plugins/Pluggable should match snapshot with null pluggableId 1`] = `
"presenceChannel": null,
"reconnectCallback": null,
"reconnectListeners": Set {},
"reconnecting": false,
"responseCallbacks": Object {},
"responseSequence": 1,
"serverSequence": 0,
Expand Down Expand Up @@ -366,6 +387,12 @@ exports[`plugins/Pluggable should match snapshot with valid pluggableId 1`] = `
<ProfilePopoverPlugin
webSocketClient={
WebSocketClient {
"_currentUserId": undefined,
"_currentUserTeamId": undefined,
"_presenceChannelId": undefined,
"_teamId": undefined,
"_userId": undefined,
"_userTeamId": undefined,
"closeCallback": null,
"closeListeners": Set {},
"conn": null,
Expand All @@ -391,6 +418,7 @@ exports[`plugins/Pluggable should match snapshot with valid pluggableId 1`] = `
"presenceChannel": null,
"reconnectCallback": null,
"reconnectListeners": Set {},
"reconnecting": false,
"responseCallbacks": Object {},
"responseSequence": 1,
"serverSequence": 0,
Expand Down
73 changes: 58 additions & 15 deletions webapp/platform/client/src/websocket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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() {
Expand Down Expand Up @@ -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) {
// 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();
Expand Down

0 comments on commit ab8499a

Please sign in to comment.