fix: prevent background Laya rebuilds during playback
Ensure automatic live projection rebuilds use the algorithmic path so Laya identity batches are not launched during live list playback or background sync. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
157
test/t35LayaPerfRegression.test.js
Normal file
157
test/t35LayaPerfRegression.test.js
Normal file
@ -0,0 +1,157 @@
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const Database = require('better-sqlite3');
|
||||
const {
|
||||
ensureColumns,
|
||||
LIVE_PROJECTION_COLUMNS,
|
||||
LIVE_PROJECTION_SCHEMA_SQL
|
||||
} = require('../server/db/liveProjectionSchema');
|
||||
const appDb = require('../server/db');
|
||||
const layaModule = require('../server/services/layaService');
|
||||
const liveProjection = require('../server/services/liveProjectionService');
|
||||
|
||||
const liveRouteSource = fs.readFileSync(path.join(__dirname, '..', 'server', 'routes', 'live.js'), 'utf8');
|
||||
|
||||
function createDb() {
|
||||
const db = new Database(':memory:');
|
||||
db.exec(`
|
||||
CREATE TABLE categories (
|
||||
id TEXT PRIMARY KEY,
|
||||
source_id INTEGER NOT NULL,
|
||||
category_id TEXT NOT NULL,
|
||||
type TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
parent_id TEXT,
|
||||
is_hidden INTEGER DEFAULT 0,
|
||||
data JSON
|
||||
);
|
||||
CREATE TABLE playlist_items (
|
||||
id TEXT PRIMARY KEY,
|
||||
source_id INTEGER NOT NULL,
|
||||
item_id TEXT NOT NULL,
|
||||
type TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
category_id TEXT,
|
||||
parent_id TEXT,
|
||||
stream_icon TEXT,
|
||||
stream_url TEXT,
|
||||
container_extension TEXT,
|
||||
rating REAL,
|
||||
year TEXT,
|
||||
added_at TEXT,
|
||||
is_hidden INTEGER DEFAULT 0,
|
||||
is_favorite INTEGER DEFAULT 0,
|
||||
data JSON
|
||||
);
|
||||
CREATE TABLE favorites (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER NOT NULL,
|
||||
source_id INTEGER NOT NULL,
|
||||
item_id TEXT NOT NULL,
|
||||
item_type TEXT NOT NULL
|
||||
);
|
||||
`);
|
||||
ensureColumns(db, 'playlist_items', LIVE_PROJECTION_COLUMNS);
|
||||
db.exec(LIVE_PROJECTION_SCHEMA_SQL);
|
||||
return db;
|
||||
}
|
||||
|
||||
function seedChannel(db, sourceId, itemId, name) {
|
||||
db.prepare(`
|
||||
INSERT INTO playlist_items
|
||||
(id, source_id, item_id, type, name, category_id, stream_icon, stream_url, data)
|
||||
VALUES (?, ?, ?, 'live', ?, 'sports', '', ?, '{}')
|
||||
`).run(`${sourceId}:${itemId}`, sourceId, itemId, name, `https://streams.test/${itemId}.m3u8`);
|
||||
}
|
||||
|
||||
async function simulateLiveListOpen(database) {
|
||||
let state = liveProjection.projectionState(database);
|
||||
if (state.status !== 'success' && state.status !== 'building') {
|
||||
state = await liveProjection.startRebuild(database, {
|
||||
mode: 'algo',
|
||||
schedule: callback => callback()
|
||||
}).promise;
|
||||
}
|
||||
return liveProjection.getChannelPage({ includeHidden: false, userId: 7 }, database, {
|
||||
iptvOrgCatalog: { findMatch: () => null },
|
||||
epgMatching: { findBestMatch: () => null }
|
||||
});
|
||||
}
|
||||
|
||||
test('opening the live list with a missing projection must not start a global Laya identity batch', async () => {
|
||||
assert.match(
|
||||
liveRouteSource,
|
||||
/liveProjection\.startRebuild\(null, \{ mode: 'algo' \}\)/,
|
||||
'the live-list repair path must explicitly request the algorithmic rebuild mode'
|
||||
);
|
||||
const db = createDb();
|
||||
for (let index = 0; index < 12; index++) {
|
||||
seedChannel(db, 1, `existing-${index}`, `beIN Sports 1 regional ${index}`);
|
||||
}
|
||||
|
||||
let layaCalls = 0;
|
||||
let layaPairCount = 0;
|
||||
const originalSettingsGet = appDb.settings.get;
|
||||
const OriginalLayaService = layaModule.LayaService;
|
||||
appDb.settings.get = async () => ({ ...appDb.getDefaultSettings(), languageDetectionMode: 'laya' });
|
||||
layaModule.LayaService = class {
|
||||
async identityHintBatch(pairs) {
|
||||
layaCalls += 1;
|
||||
layaPairCount += pairs.length;
|
||||
return pairs.map(pair => ({
|
||||
id: pair.id,
|
||||
sameIdentityProbability: 0.9,
|
||||
confidence: 0.9,
|
||||
family: 'bein sports',
|
||||
number: '1'
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
const page = await simulateLiveListOpen(db);
|
||||
assert.ok(page.channels.length > 0);
|
||||
assert.equal(layaCalls, 0, `unexpected Laya identity batches while opening live list; batches=${layaCalls}, pairs=${layaPairCount}`);
|
||||
} finally {
|
||||
appDb.settings.get = originalSettingsGet;
|
||||
layaModule.LayaService = OriginalLayaService;
|
||||
db.close();
|
||||
}
|
||||
});
|
||||
|
||||
test('background live sync rebuilds must not start Laya identity batches in configured Laya mode', async () => {
|
||||
const db = createDb();
|
||||
for (let index = 0; index < 12; index++) {
|
||||
seedChannel(db, 1, `existing-${index}`, `beIN Sports 1 regional ${index}`);
|
||||
}
|
||||
|
||||
let layaCalls = 0;
|
||||
let layaPairCount = 0;
|
||||
const originalSettingsGet = appDb.settings.get;
|
||||
const OriginalLayaService = layaModule.LayaService;
|
||||
appDb.settings.get = async () => ({ ...appDb.getDefaultSettings(), languageDetectionMode: 'laya' });
|
||||
layaModule.LayaService = class {
|
||||
async identityHintBatch(pairs) {
|
||||
layaCalls += 1;
|
||||
layaPairCount += pairs.length;
|
||||
return pairs.map(pair => ({
|
||||
id: pair.id,
|
||||
sameIdentityProbability: 0.9,
|
||||
confidence: 0.9,
|
||||
family: 'bein sports',
|
||||
number: '1'
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
await liveProjection.queueRebuild(db);
|
||||
assert.equal(layaCalls, 0, `unexpected Laya identity batches during background sync rebuild; batches=${layaCalls}, pairs=${layaPairCount}`);
|
||||
} finally {
|
||||
appDb.settings.get = originalSettingsGet;
|
||||
layaModule.LayaService = OriginalLayaService;
|
||||
db.close();
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user