セッションの再利用
ブラウザレンダリングワーカーのパフォーマンスを向上させる最良の方法は、セッションを再利用することです。その方法の一つは、Durable Objectsを使用することで、ワーカーからブラウザへの長時間接続を維持できます。もう一つの方法は、作業が終わった後にブラウザを開いたままにしておき、新しいリクエストがあるたびにそのセッションに接続することです。
要するに、browser.disconnect()を使用し、browser.close()の代わりに、利用可能なセッションがある場合は新しいブラウザセッションを立ち上げるのではなく、puppeteer.connect(env.MY_BROWSER, sessionID)を使用します。
Cloudflare Workersは、インフラストラクチャを設定または維持することなく、新しいアプリケーションを作成したり、既存のアプリケーションを拡張したりすることができるサーバーレス実行環境を提供します。あなたのワーカーアプリケーションは、スクリーンショットを撮るなどのアクションを実行するためにヘッドレスブラウザと対話するためのコンテナです。
次のコマンドを実行して、browser-workerという名前の新しいワーカープロジェクトを作成します。
npm create cloudflare@latest -- browser-workeryarn create cloudflare@latest browser-workerpnpm create cloudflare@latest browser-workerFor setup, select the following options:
- For What would you like to start with?, choose
Hello Worldの例. - For Which template would you like to use?, choose
Hello Worldワーカー. - For Which language do you want to use?, choose
TypeScript. - For Do you want to use git for version control?, choose
Yes. - For Do you want to deploy your application?, choose
No(we will be making some changes before deploying).
browser-workerディレクトリ内で、CloudflareのPuppeteerのフォークをインストールします。
npm install @cloudflare/puppeteer --save-devname = "browser-worker"main = "src/index.ts"compatibility_date = "2023-03-14"compatibility_flags = [ "nodejs_compat" ]
browser = { binding = "MYBROWSER" }以下のスクリプトは、現在実行中のセッションを取得することから始まります。ワーカー接続を持たないセッションがあれば、ランダムなセッションIDを選択し、それに接続しようとします(puppeteer.connect(..))。接続に失敗した場合や、最初から実行中のセッションがなかった場合は、新しいブラウザセッションを立ち上げます(puppeteer.launch(..))。その後、ウェブサイトにアクセスし、DOMを取得します。作業が完了したら、接続を切断します(browser.disconnect())、これにより他のワーカーが接続できるようになります。
ブラウザがアイドル状態、つまり現在の制限を超えてコマンドを受け取らない場合、自動的に閉じるため、ブラウザを生かしておくためには十分なリクエストを毎分送信する必要があります。
import puppeteer from "@cloudflare/puppeteer";
interface Env { MYBROWSER: Fetcher;}
export default { async fetch(request: Request, env: Env): Promise<Response> { const url = new URL(request.url); let reqUrl = url.searchParams.get("url") || "https://example.com"; reqUrl = new URL(reqUrl).toString(); // 正規化
// 開いているセッションからランダムに選択 let sessionId = await this.getRandomSession(env.MYBROWSER); let browser, launched; if (sessionId) { try { browser = await puppeteer.connect(env.MYBROWSER, sessionId); } catch (e) { // 別のワーカーが先に接続した可能性があります console.log(`Failed to connect to ${sessionId}. Error ${e}`); } } if (!browser) { // 開いているセッションがない場合、新しいセッションを立ち上げる browser = await puppeteer.launch(env.MYBROWSER); launched = true; }
sessionId = browser.sessionId(); // 現在のセッションIDを取得
// ここで作業を行う const page = await browser.newPage(); const response = await page.goto(reqUrl); const html = await response!.text();
// すべての作業が完了したので、接続を解放(重要!) await browser.disconnect();
return new Response( `${launched ? "立ち上げました" : "接続しました"} ${sessionId} \n-----\n` + html, { headers: { "content-type": "text/plain", }, }, ); },
// ランダムな空きセッションを選択 // 他のカスタムロジックを使用することもできます async getRandomSession(endpoint: puppeteer.BrowserWorker): Promise<string> { const sessions: puppeteer.ActiveSession[] = await puppeteer.sessions(endpoint); console.log(`セッション: ${JSON.stringify(sessions)}`); const sessionsIds = sessions .filter((v) => { return !v.connectionId; // 接続されているワーカーのあるセッションを除外 }) .map((v) => { return v.sessionId; }); if (sessionsIds.length === 0) { return; }
const sessionId = sessionsIds[Math.floor(Math.random() * sessionsIds.length)];
return sessionId!; },};puppeteer.sessions()に加えて、セッション管理を容易にするための他のメソッドも追加しました - 詳細はこちらを確認してください。
npx wrangler dev --remoteを実行して、Cloudflareのグローバルネットワークにデプロイする前に、リモートでワーカーをテストします。ブラウザレンダリングのローカルモードサポートは存在しないため、--remoteが必要です。
テストするには、次のURLにアクセスします:
<LOCAL_HOST_URL>/?url=https://example.com
npx wrangler deployを実行して、ワーカーをCloudflareのグローバルネットワークにデプロイし、次のURLにアクセスします:
<YOUR_WORKER>.<YOUR_SUBDOMAIN>.workers.dev/?url=https://example.com