From d05d5f0b371a86336591576ea202ede4a46b596f Mon Sep 17 00:00:00 2001 From: Ben Date: Sun, 7 Jun 2026 23:32:49 -0400 Subject: [PATCH] Bound info endpoint cold cache work --- src/app.controller.ts | 47 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/src/app.controller.ts b/src/app.controller.ts index 66559b2..378c1f7 100644 --- a/src/app.controller.ts +++ b/src/app.controller.ts @@ -43,9 +43,22 @@ export class AppController { return cachedResult; } - const blockData = await this.blocksService.getFoundBlocks(); - const highScores = await this.addressSettingsService.getHighScores(); - const poolAuthority = await this.stratumV2Service.getPoolAuthorityPublicKey(); + let usedFallback = false; + const withInfoTimeout = async (label: string, promise: Promise, fallback: T): Promise => { + return await this.withTimeout(label, promise, fallback, () => { + usedFallback = true; + }); + }; + + const [blockData, highScores, poolAuthority, userAgentReport] = await Promise.all([ + withInfoTimeout('found blocks', this.blocksService.getFoundBlocks(), []), + withInfoTimeout('high scores', this.addressSettingsService.getHighScores(), []), + withInfoTimeout('SV2 authority', this.stratumV2Service.getPoolAuthorityPublicKey(), { + publicKey: '', + configured: false + }), + withInfoTimeout('user agent report', this.userAgentReportService.getReport(), []), + ]); const other: { count: number, @@ -56,7 +69,7 @@ export class AppController { bestDifficulty: 0, totalHashRate: 0 }; - const userAgents: UserAgentReportView[] = (await this.userAgentReportService.getReport()).reduce((pre, cur, idx, arr) => { + const userAgents: UserAgentReportView[] = userAgentReport.reduce((pre, cur, idx, arr) => { // If less than 10Th/s and less than 100 devices, add to 'other' if (parseInt(cur.totalHashRate) < 10000000000000 && parseInt(cur.count) < 200) { other.totalHashRate += parseFloat(cur.totalHashRate); @@ -86,7 +99,7 @@ export class AppController { }; // Match the pre-Timescale dashboard cache behavior; live accounting is exposed separately. - await this.setCached(CACHE_KEY, data, 5 * 60 * 1000); + await this.setCached(CACHE_KEY, data, usedFallback ? 15 * 1000 : 5 * 60 * 1000); return data; @@ -187,4 +200,28 @@ export class AppController { ]); } + private async withTimeout( + label: string, + promise: Promise, + fallback: T, + onTimeout: () => void, + timeoutMs = 1500 + ): Promise { + let timeout: NodeJS.Timeout; + const timeoutPromise = new Promise(resolve => { + timeout = setTimeout(() => { + onTimeout(); + console.error(`/api/info ${label} timed out after ${timeoutMs}ms`); + resolve(fallback); + }, timeoutMs); + timeout.unref?.(); + }); + + try { + return await Promise.race([promise, timeoutPromise]); + } finally { + clearTimeout(timeout); + } + } + }