perf(app): cut idle renderer CPU and unbounded memory growth (#1724)

This commit is contained in:
Hampus authored and GitHub committed 2026-08-18 23:13:42 +02:00
1 parent b4a5eb77a8
commit 5660972c71
13 files changed
+453 -345

No files matched your search

@@ -39,6 +39,7 @@ type Listener = () => void;
const EMPTY_REACTIONS: ReadonlyArray<MessageReaction> = Object.freeze([]);
const EMPTY_USERS: ReadonlyArray<User> = Object.freeze([]);
const MAX_TRACKED_REACTION_REQUEST_KEYS = 512;
const createEmptyReactorEntry = (requestSerial = 0): ReactorEntry => ({
snapshot: createReactionUsersSnapshot(requestSerial),
});
@@ -68,6 +69,7 @@ export class MessageReactionsManager {
private reactors: Map<string, ReactorEntry> = new Map();
private _keysByMessage: Map<string, Set<string>> = new Map();
private retiredReactionRequests: Map<string, number> = new Map();
private inFlightReactionRequests: Map<string, Set<number>> = new Map();
private messageListeners: Map<string, Set<Listener>> = new Map();
private reactionListeners: Map<string, Set<Listener>> = new Map();
private transactionDepth = 0;
@@ -247,7 +249,9 @@ export class MessageReactionsManager {
handleFetchPending(messageId: string, emoji: ReactionEmoji): number {
const entry = this.getOrCreateReactorEntry(messageId, emoji);
this.commitReactorEvent(messageId, emoji, entry, {type: 'fetch.pending'});
return entry.snapshot.context.activeRequestId ?? entry.snapshot.context.requestSerial;
const requestId = entry.snapshot.context.activeRequestId ?? entry.snapshot.context.requestSerial;
this.trackInFlightRequest(getReactionKey(messageId, emoji), requestId);
return requestId;
}
handleFetchSuccess(
@@ -261,7 +265,9 @@ export class MessageReactionsManager {
nextAfter?: string | null,
): void {
const key = getReactionKey(messageId, emoji);
if (this.shouldIgnoreFetchResult(key, requestId)) return;
const ignored = this.shouldIgnoreFetchResult(key, requestId);
this.settleInFlightRequest(key, requestId);
if (ignored) return;
const entry = this.getOrCreateReactorEntry(messageId, emoji);
Users.cacheUsers(users.slice());
this.commitReactorEvent(messageId, emoji, entry, {
@@ -288,7 +294,9 @@ export class MessageReactionsManager {
nextAfter?: string | null,
): void {
const key = getReactionKey(messageId, emoji);
if (this.shouldIgnoreFetchResult(key, requestId)) return;
const ignored = this.shouldIgnoreFetchResult(key, requestId);
this.settleInFlightRequest(key, requestId);
if (ignored) return;
const entry = this.getOrCreateReactorEntry(messageId, emoji);
Users.cacheUsers(users.slice());
this.commitReactorEvent(messageId, emoji, entry, {
@@ -306,7 +314,9 @@ export class MessageReactionsManager {
handleFetchError(messageId: string, emoji: ReactionEmoji, requestId?: number): void {
const key = getReactionKey(messageId, emoji);
if (this.shouldIgnoreFetchResult(key, requestId)) return;
const ignored = this.shouldIgnoreFetchResult(key, requestId);
this.settleInFlightRequest(key, requestId);
if (ignored) return;
this.commitReactorEvent(messageId, emoji, this.getOrCreateReactorEntry(messageId, emoji), {
type: 'fetch.error',
requestId,
@@ -370,10 +380,37 @@ export class MessageReactionsManager {
}
private retireReactionEntry(key: string, entry = this.reactors.get(key)): void {
this.reactors.delete(key);
if (!this.inFlightReactionRequests.has(key)) {
this.retiredReactionRequests.delete(key);
return;
}
const requestSerial = entry?.snapshot.context.requestSerial ?? 0;
const nextRequestId = Math.max(this.retiredReactionRequests.get(key) ?? 0, requestSerial);
this.retiredReactionRequests.set(key, nextRequestId);
this.reactors.delete(key);
}
private trackInFlightRequest(key: string, requestId: number): void {
const requestIds = this.inFlightReactionRequests.get(key) ?? new Set<number>();
requestIds.add(requestId);
this.inFlightReactionRequests.delete(key);
this.inFlightReactionRequests.set(key, requestIds);
while (this.inFlightReactionRequests.size > MAX_TRACKED_REACTION_REQUEST_KEYS) {
const oldest = this.inFlightReactionRequests.keys().next();
if (oldest.done) break;
this.inFlightReactionRequests.delete(oldest.value);
this.retiredReactionRequests.delete(oldest.value);
}
}
private settleInFlightRequest(key: string, requestId?: number): void {
if (requestId == null) return;
const requestIds = this.inFlightReactionRequests.get(key);
if (!requestIds) return;
requestIds.delete(requestId);
if (requestIds.size > 0) return;
this.inFlightReactionRequests.delete(key);
this.retiredReactionRequests.delete(key);
}
private shouldIgnoreFetchResult(key: string, requestId?: number): boolean {