mirror of
https://github.com/RocketChat/Rocket.Chat.git
synced 2025-12-28 06:47:25 +00:00
fix: high cpu usage with large amount of channels (#37395)
This commit is contained in:
parent
b4cf623a04
commit
e7be28bfda
5
.changeset/quiet-cars-smile.md
Normal file
5
.changeset/quiet-cars-smile.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"@rocket.chat/meteor": patch
|
||||
---
|
||||
|
||||
Fixes client slowdown for users with large amount of channels
|
||||
@ -1,6 +1,6 @@
|
||||
import { manageFavicon } from '@rocket.chat/favicon';
|
||||
import { useSession, useSessionDispatch, useUserPreference, useUserSubscriptions } from '@rocket.chat/ui-contexts';
|
||||
import { useEffect } from 'react';
|
||||
import { useEffect, useRef } from 'react';
|
||||
|
||||
import { useFireGlobalEvent } from '../../../../hooks/useFireGlobalEvent';
|
||||
|
||||
@ -8,6 +8,8 @@ const query = { open: { $ne: false }, hideUnreadStatus: { $ne: true }, archived:
|
||||
const options = { fields: { unread: 1, alert: 1, rid: 1, t: 1, name: 1, ls: 1, unreadAlert: 1, fname: 1, prid: 1 } };
|
||||
const updateFavicon = manageFavicon();
|
||||
|
||||
type UnreadData = { unread: number; alert: boolean | undefined; unreadAlert: string | undefined };
|
||||
|
||||
export const useUnread = () => {
|
||||
const unreadAlertEnabled = useUserPreference('unreadAlert');
|
||||
const setUnread = useSessionDispatch('unread');
|
||||
@ -18,37 +20,48 @@ export const useUnread = () => {
|
||||
|
||||
const subscriptions = useUserSubscriptions(query, options);
|
||||
|
||||
// We keep a lightweight snapshot of the last emitted per-subscription unread state so we only
|
||||
// fire "unread-changed-by-subscription" for subscriptions whose unread-relevant fields changed.
|
||||
// Previously we emitted one global event per subscription on ANY change, which scaled O(N)
|
||||
// with the user subscription count (thousands) for every single message event, dominating CPU.
|
||||
const prevSubsRef = useRef(new Map<string, UnreadData>());
|
||||
|
||||
useEffect(() => {
|
||||
let unreadAlert: false | '•' = false;
|
||||
let badgeIndicator: false | '•' = false;
|
||||
let unreadCount = 0;
|
||||
const nextSnapshot = new Map<string, UnreadData>();
|
||||
|
||||
const unreadCount = subscriptions.reduce((ret, subscription) => {
|
||||
fireEventUnreadChangedBySubscription(subscription);
|
||||
for (const subscription of subscriptions) {
|
||||
const { rid, unread: unreadValue, alert, unreadAlert: subscriptionUnreadAlert } = subscription;
|
||||
const prev = prevSubsRef.current.get(rid);
|
||||
// Emit per-sub event only if something that influences unread UI changed.
|
||||
if (!prev || prev.unread !== unreadValue || prev.alert !== alert || prev.unreadAlert !== subscriptionUnreadAlert) {
|
||||
fireEventUnreadChangedBySubscription(subscription);
|
||||
}
|
||||
nextSnapshot.set(rid, { unread: unreadValue, alert, unreadAlert: subscriptionUnreadAlert });
|
||||
|
||||
if (subscription.alert || subscription.unread > 0) {
|
||||
// Increment the total unread count.
|
||||
if (subscription.alert === true && subscription.unreadAlert !== 'nothing') {
|
||||
if (subscription.unreadAlert === 'all' || unreadAlertEnabled !== false) {
|
||||
unreadAlert = '•';
|
||||
if (alert || unreadValue > 0) {
|
||||
if (alert === true && subscriptionUnreadAlert !== 'nothing') {
|
||||
if (subscriptionUnreadAlert === 'all' || unreadAlertEnabled !== false) {
|
||||
badgeIndicator = '•';
|
||||
}
|
||||
}
|
||||
return ret + subscription.unread;
|
||||
unreadCount += unreadValue;
|
||||
}
|
||||
return ret;
|
||||
}, 0);
|
||||
}
|
||||
|
||||
prevSubsRef.current = nextSnapshot; // swap snapshot
|
||||
|
||||
if (unreadCount > 0) {
|
||||
if (unreadCount > 999) {
|
||||
setUnread('999+');
|
||||
} else {
|
||||
setUnread(unreadCount);
|
||||
}
|
||||
} else if (unreadAlert !== false) {
|
||||
setUnread(unreadAlert);
|
||||
setUnread(unreadCount > 999 ? '999+' : unreadCount);
|
||||
} else if (badgeIndicator !== false) {
|
||||
setUnread(badgeIndicator);
|
||||
} else {
|
||||
setUnread('');
|
||||
}
|
||||
|
||||
fireEventUnreadChanged(unreadCount);
|
||||
}, [setUnread, unread, subscriptions, unreadAlertEnabled, fireEventUnreadChangedBySubscription, fireEventUnreadChanged]);
|
||||
}, [setUnread, subscriptions, unreadAlertEnabled, fireEventUnreadChangedBySubscription, fireEventUnreadChanged]);
|
||||
|
||||
useEffect(() => {
|
||||
updateFavicon(unread);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user