fix: add translator queue limit, periodic cleanup, and node checks

This commit is contained in:
2026-04-15 07:27:01 -07:00
parent fba25a9081
commit 6582ddf93a
+43 -2
View File
@@ -104,7 +104,7 @@ const FALSE_POSITIVE_LANGS = new Set([
// ── Auto-suppression (repeated short phrases) ── // ── Auto-suppression (repeated short phrases) ──
const suppressionCounts = new Map<string, number>(); let suppressionCounts = new Map<string, number>();
const SUPPRESS_THRESHOLD = 3; const SUPPRESS_THRESHOLD = 3;
const MIN_LATIN_WORDS = 3; const MIN_LATIN_WORDS = 3;
const SHORT_TEXT_THRESHOLD = 15; const SHORT_TEXT_THRESHOLD = 15;
@@ -113,6 +113,7 @@ const SHORT_TEXT_THRESHOLD = 15;
let activeRequests = 0; let activeRequests = 0;
const MAX_CONCURRENT = 3; const MAX_CONCURRENT = 3;
const MAX_QUEUE = 15;
const pendingQueue: Array<() => void> = []; const pendingQueue: Array<() => void> = [];
function enqueue(fn: () => Promise<void>): void { function enqueue(fn: () => Promise<void>): void {
@@ -123,10 +124,45 @@ function enqueue(fn: () => Promise<void>): void {
if (pendingQueue.length > 0) pendingQueue.shift()!(); if (pendingQueue.length > 0) pendingQueue.shift()!();
}); });
} else { } else {
// Drop oldest if queue is full — old messages have already scrolled off-screen
if (pendingQueue.length >= MAX_QUEUE) pendingQueue.shift();
pendingQueue.push(() => enqueue(fn)); pendingQueue.push(() => enqueue(fn));
} }
} }
// ── Periodic cleanup (prevents unbounded memory growth in long sessions) ──
const CLEANUP_INTERVAL_MS = 5 * 60 * 1000;
let cleanupTimer: ReturnType<typeof setInterval> | null = null;
function startCleanup(): void {
if (cleanupTimer) return;
cleanupTimer = setInterval(() => {
// Reset suppression counts (re-learned naturally from fresh messages)
suppressionCounts = new Map();
// Prune expired sessionStorage cache entries
const now = Date.now();
const keysToRemove: string[] = [];
for (let i = 0; i < sessionStorage.length; i++) {
const key = sessionStorage.key(i);
if (!key?.startsWith(CACHE_KEY_PREFIX)) continue;
try {
const entry: CacheEntry = JSON.parse(sessionStorage.getItem(key) || '');
if (now - entry.ts > CACHE_EXPIRY_MS) keysToRemove.push(key);
} catch { keysToRemove.push(key); }
}
for (const key of keysToRemove) sessionStorage.removeItem(key);
}, CLEANUP_INTERVAL_MS);
}
function stopCleanup(): void {
if (cleanupTimer) {
clearInterval(cleanupTimer);
cleanupTimer = null;
}
}
// ── System message patterns to skip ── // ── System message patterns to skip ──
const SYSTEM_PATTERNS = [ const SYSTEM_PATTERNS = [
@@ -281,8 +317,10 @@ function processMessage(node: HTMLElement): void {
const { message, username } = extracted; const { message, username } = extracted;
enqueue(async () => { enqueue(async () => {
// Node may have been removed by chat history trimming while queued
if (!node.isConnected) return;
const result = await translateText(message); const result = await translateText(message);
if (result) appendTranslation(node, username, result.translation, result.srcLang); if (result && node.isConnected) appendTranslation(node, username, result.translation, result.srcLang);
}); });
} }
@@ -316,6 +354,7 @@ function startObserver(): void {
}); });
chatObserver.observe(chatList, { childList: true }); chatObserver.observe(chatList, { childList: true });
startCleanup();
_con.log('[KCC-TL] Chat observer active'); _con.log('[KCC-TL] Chat observer active');
}, 500); }, 500);
} }
@@ -329,6 +368,8 @@ function stopObserver(): void {
chatObserver.disconnect(); chatObserver.disconnect();
chatObserver = null; chatObserver = null;
} }
stopCleanup();
pendingQueue.length = 0;
} }
// ── Public API ── // ── Public API ──