good stuff
This commit is contained in:
parent
ea8389ef40
commit
f4de0eeb9f
39 changed files with 5165 additions and 348 deletions
|
|
@ -50,6 +50,10 @@ export class ScreenshotCache {
|
|||
normalized.tab = params.get('tab')!;
|
||||
}
|
||||
|
||||
if (params.get('og')) {
|
||||
normalized.og = params.get('og')!;
|
||||
}
|
||||
|
||||
if (params.get('path')) {
|
||||
normalized.path = params.get('path')!;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -180,29 +180,49 @@ async function releasePage(page: Page): Promise<void> {
|
|||
* Pre-warm the browser and populate the network cache by loading the app once.
|
||||
* Subsequent screenshots benefit from cached JS/CSS bundles, map tiles,
|
||||
* and V8 compiled bytecode — eliminating cold-start latency.
|
||||
*
|
||||
* Retries with exponential backoff if the frontend isn't up yet (common during
|
||||
* docker-compose startup where the frontend may still be installing/building).
|
||||
*/
|
||||
export async function initialize(appUrl: string): Promise<void> {
|
||||
console.log('Pre-warming browser and caches...');
|
||||
const page = await createPage();
|
||||
try {
|
||||
await page.goto(`${appUrl}/?screenshot=1`, {
|
||||
waitUntil: 'load',
|
||||
timeout: 30_000,
|
||||
});
|
||||
// Wait for the app to fully load and cache all resources
|
||||
|
||||
const MAX_RETRIES = 10;
|
||||
const INITIAL_DELAY_MS = 2_000;
|
||||
|
||||
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
|
||||
const page = await createPage();
|
||||
try {
|
||||
await page.waitForFunction('window.__screenshot_ready === true', {
|
||||
timeout: READY_TIMEOUT,
|
||||
await page.goto(`${appUrl}/?screenshot=1`, {
|
||||
waitUntil: 'load',
|
||||
timeout: 30_000,
|
||||
});
|
||||
} catch {
|
||||
// Non-fatal — cache will still have JS/CSS/tiles from the partial load
|
||||
// Wait for the app to fully load and cache all resources
|
||||
try {
|
||||
await page.waitForFunction('window.__screenshot_ready === true', {
|
||||
timeout: READY_TIMEOUT,
|
||||
});
|
||||
} catch {
|
||||
// Non-fatal — cache will still have JS/CSS/tiles from the partial load
|
||||
}
|
||||
console.log(`Pre-warm complete. Cache: ${networkCache.stats()}`);
|
||||
await page.close().catch(() => {});
|
||||
await warmPool();
|
||||
return;
|
||||
} catch (err) {
|
||||
await page.close().catch(() => {});
|
||||
if (attempt === MAX_RETRIES) {
|
||||
console.warn(`Pre-warm failed after ${MAX_RETRIES} attempts (non-fatal):`, err);
|
||||
} else {
|
||||
const delay = INITIAL_DELAY_MS * Math.pow(2, attempt - 1);
|
||||
console.log(`Pre-warm attempt ${attempt}/${MAX_RETRIES} failed, retrying in ${(delay / 1000).toFixed(0)}s...`);
|
||||
await new Promise((resolve) => setTimeout(resolve, delay));
|
||||
}
|
||||
}
|
||||
console.log(`Pre-warm complete. Cache: ${networkCache.stats()}`);
|
||||
} catch (err) {
|
||||
console.warn('Pre-warm failed (non-fatal):', err);
|
||||
} finally {
|
||||
await page.close().catch(() => {});
|
||||
}
|
||||
|
||||
// Even if pre-warm failed, still warm the page pool so first real
|
||||
// screenshot requests don't pay for page creation
|
||||
await warmPool();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue