Initial commit
This commit is contained in:
118
templates/session-reuse.ts
Normal file
118
templates/session-reuse.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
// Session Reuse Pattern
|
||||
// Optimize performance by reusing browser sessions instead of launching new ones
|
||||
|
||||
import puppeteer, { Browser } from "@cloudflare/puppeteer";
|
||||
|
||||
interface Env {
|
||||
MYBROWSER: Fetcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or create a browser instance
|
||||
* Tries to connect to existing session first, launches new one if needed
|
||||
*/
|
||||
async function getBrowser(env: Env): Promise<{ browser: Browser; launched: boolean }> {
|
||||
// Check for available sessions
|
||||
const sessions = await puppeteer.sessions(env.MYBROWSER);
|
||||
|
||||
// Find sessions without active connections
|
||||
const freeSessions = sessions.filter((s) => !s.connectionId);
|
||||
|
||||
if (freeSessions.length > 0) {
|
||||
// Try to connect to existing session
|
||||
try {
|
||||
console.log("Connecting to existing session:", freeSessions[0].sessionId);
|
||||
const browser = await puppeteer.connect(env.MYBROWSER, freeSessions[0].sessionId);
|
||||
return { browser, launched: false };
|
||||
} catch (error) {
|
||||
console.log("Failed to connect, launching new browser:", error);
|
||||
}
|
||||
}
|
||||
|
||||
// Check limits before launching
|
||||
const limits = await puppeteer.limits(env.MYBROWSER);
|
||||
if (limits.allowedBrowserAcquisitions === 0) {
|
||||
throw new Error(
|
||||
`Rate limit reached. Retry after ${limits.timeUntilNextAllowedBrowserAcquisition}ms`
|
||||
);
|
||||
}
|
||||
|
||||
// Launch new session
|
||||
console.log("Launching new browser session");
|
||||
const browser = await puppeteer.launch(env.MYBROWSER);
|
||||
return { browser, launched: true };
|
||||
}
|
||||
|
||||
export default {
|
||||
async fetch(request: Request, env: Env): Promise<Response> {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const url = searchParams.get("url") || "https://example.com";
|
||||
|
||||
try {
|
||||
// Get or create browser
|
||||
const { browser, launched } = await getBrowser(env);
|
||||
const sessionId = browser.sessionId();
|
||||
|
||||
console.log({
|
||||
sessionId,
|
||||
launched,
|
||||
message: launched ? "New browser launched" : "Reused existing session",
|
||||
});
|
||||
|
||||
// Do work
|
||||
const page = await browser.newPage();
|
||||
await page.goto(url, {
|
||||
waitUntil: "networkidle0",
|
||||
timeout: 30000,
|
||||
});
|
||||
|
||||
const screenshot = await page.screenshot();
|
||||
await page.close();
|
||||
|
||||
// IMPORTANT: Disconnect (don't close) to keep session alive for reuse
|
||||
await browser.disconnect();
|
||||
|
||||
return new Response(screenshot, {
|
||||
headers: {
|
||||
"content-type": "image/png",
|
||||
"x-session-id": sessionId,
|
||||
"x-session-reused": launched ? "false" : "true",
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
error: error instanceof Error ? error.message : "Unknown error",
|
||||
}),
|
||||
{
|
||||
status: 500,
|
||||
headers: { "content-type": "application/json" },
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Key Concepts:
|
||||
*
|
||||
* 1. puppeteer.sessions() - List all active sessions
|
||||
* 2. puppeteer.connect() - Connect to existing session
|
||||
* 3. browser.disconnect() - Disconnect WITHOUT closing (keeps session alive)
|
||||
* 4. browser.close() - Terminate session completely
|
||||
* 5. puppeteer.limits() - Check rate limits before launching
|
||||
*
|
||||
* Benefits:
|
||||
* - Faster response times (no cold start)
|
||||
* - Lower concurrency usage
|
||||
* - Better resource utilization
|
||||
*
|
||||
* Trade-offs:
|
||||
* - Sessions time out after 60s idle (extend with keep_alive)
|
||||
* - Must handle connection failures gracefully
|
||||
* - Need to track which sessions are available
|
||||
*
|
||||
* Response Headers:
|
||||
* - x-session-id: Browser session ID
|
||||
* - x-session-reused: true if reused existing session
|
||||
*/
|
||||
Reference in New Issue
Block a user