Keep HTTP responsive during confluence replay.
Boot replay was a tight CPU loop that wedged the Unraid backend, so login hit the 8s client timeout. Yield every few as-of dates, shorten the boot ledger fill, and make /health a cheap liveness check.
This commit is contained in:
@@ -301,7 +301,12 @@ export async function runConfluenceReplay(
|
|||||||
const weeklyFull = await provider.resolveAsOf(symbol, '1wk', '9999-12-31');
|
const weeklyFull = await provider.resolveAsOf(symbol, '1wk', '9999-12-31');
|
||||||
const benchFull = await provider.resolveAsOf(BENCHMARK_SYMBOL, '1d', '9999-12-31');
|
const benchFull = await provider.resolveAsOf(BENCHMARK_SYMBOL, '1d', '9999-12-31');
|
||||||
|
|
||||||
|
let asOfN = 0;
|
||||||
for (const asOf of slice) {
|
for (const asOf of slice) {
|
||||||
|
asOfN += 1;
|
||||||
|
if (asOfN % 4 === 0) {
|
||||||
|
await new Promise<void>((r) => setImmediate(r));
|
||||||
|
}
|
||||||
const dailyCut = daily.candles.filter((c) => (c.ts ?? '').slice(0, 10) <= asOf);
|
const dailyCut = daily.candles.filter((c) => (c.ts ?? '').slice(0, 10) <= asOf);
|
||||||
const weeklyCut = weeklyFull.candles.filter((c) => (c.ts ?? '').slice(0, 10) <= asOf);
|
const weeklyCut = weeklyFull.candles.filter((c) => (c.ts ?? '').slice(0, 10) <= asOf);
|
||||||
const benchCut = benchFull.candles.filter((c) => (c.ts ?? '').slice(0, 10) <= asOf);
|
const benchCut = benchFull.candles.filter((c) => (c.ts ?? '').slice(0, 10) <= asOf);
|
||||||
@@ -391,6 +396,7 @@ export async function fillLearningLedger(
|
|||||||
complete: batch.complete,
|
complete: batch.complete,
|
||||||
};
|
};
|
||||||
if (batch.evaluationsStored === 0) break;
|
if (batch.evaluationsStored === 0) break;
|
||||||
|
await new Promise<void>((r) => setImmediate(r));
|
||||||
}
|
}
|
||||||
return { ...last, ledger: await learningLedgerStatus(db, cache) };
|
return { ...last, ledger: await learningLedgerStatus(db, cache) };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -264,7 +264,7 @@ async function confluenceTick(label: string): Promise<void> {
|
|||||||
} = await import('./confluence/confluenceEngine.ts');
|
} = await import('./confluence/confluenceEngine.ts');
|
||||||
const { CONFLUENCE_LEARNING_UNIVERSE } = await import('./confluence/confluenceSeed.ts');
|
const { CONFLUENCE_LEARNING_UNIVERSE } = await import('./confluence/confluenceSeed.ts');
|
||||||
const replay = label === 'boot'
|
const replay = label === 'boot'
|
||||||
? await fillLearningLedger(database, cache, 75_000)
|
? await fillLearningLedger(database, cache, 12_000)
|
||||||
: await runConfluenceReplay(database, cache, {
|
: await runConfluenceReplay(database, cache, {
|
||||||
symbols: CONFLUENCE_LEARNING_UNIVERSE,
|
symbols: CONFLUENCE_LEARNING_UNIVERSE,
|
||||||
symbolsPerTick: LEARNING_REPLAY_SYMBOLS,
|
symbolsPerTick: LEARNING_REPLAY_SYMBOLS,
|
||||||
@@ -331,7 +331,9 @@ const server = createServer(async (req, res) => {
|
|||||||
const url = new URL(req.url ?? '/', `http://localhost:${PORT}`);
|
const url = new URL(req.url ?? '/', `http://localhost:${PORT}`);
|
||||||
if (url.pathname === '/health') {
|
if (url.pathname === '/health') {
|
||||||
res.writeHead(200, { 'content-type': 'application/json' });
|
res.writeHead(200, { 'content-type': 'application/json' });
|
||||||
res.end(JSON.stringify({ ok: true, queue: queue.health() }));
|
// Cheap liveness only. queue.health() is a full SQLite scan and must not
|
||||||
|
// ride the docker healthcheck / login path.
|
||||||
|
res.end(JSON.stringify({ ok: true }));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (url.pathname.startsWith('/api/trpc')) {
|
if (url.pathname.startsWith('/api/trpc')) {
|
||||||
|
|||||||
+2
-1
@@ -1008,7 +1008,8 @@ export const api = {
|
|||||||
},
|
},
|
||||||
auth: {
|
auth: {
|
||||||
signup: (email: string, password: string) => trpcMutate<{ userId: string }>("auth.signup", { email, password }),
|
signup: (email: string, password: string) => trpcMutate<{ userId: string }>("auth.signup", { email, password }),
|
||||||
login: (email: string, password: string, totp?: string) => trpcMutate<{ userId: string }>("auth.login", { email, password, ...(totp ? { totp } : {}) }),
|
login: (email: string, password: string, totp?: string) =>
|
||||||
|
trpcMutate<{ userId: string }>("auth.login", { email, password, ...(totp ? { totp } : {}) }, 20_000),
|
||||||
logout: () => trpcMutate<{ ok: boolean }>("auth.logout", {}),
|
logout: () => trpcMutate<{ ok: boolean }>("auth.logout", {}),
|
||||||
changePassword: (current: string, next: string) =>
|
changePassword: (current: string, next: string) =>
|
||||||
trpcMutate<{ ok: boolean }>("auth.changePassword", { current, next }),
|
trpcMutate<{ ok: boolean }>("auth.changePassword", { current, next }),
|
||||||
|
|||||||
Reference in New Issue
Block a user