AWS LambdaでPlayWright(chromium)を動かした
起こったこと
特定のサイトのスクショを取りたい。WebAPIで叩いて動くAWS Lambda上でPlayWrightを起動し、スクショを取って返却するようにした。
これを実装するには結構な時間がかかったので共有したくなった。
ただし、実行速度が遅い。
正しくは値を返却するまでの時間がものすごくかかる。およそ15秒待たないと画像が表示されない。LambdaLayerなどを使うと早くなるのだろうか。誰か教えてくれ。
AWS CDKでの書き方
NodejsFunction
を使いたい場合、bundling
プロパティに依存するモジュールを記載すると動くようだ。
import { Duration, Size, Cors } from "aws-cdk-lib"; import { Construct } from "constructs"; import { Runtime } from "aws-cdk-lib/aws-lambda"; import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs"; export class LambdaWithCdkStack extends Stack { constructor(scope: Construct, id: string, props: CustomizedProps) { super(scope, id, props); const nodeFunction = new NodejsFunction(this, `node_function`, { entry: "./lambda/handler.ts", handler: "handler", runtime: Runtime.NODEJS_16_X, timeout: Duration.seconds(60), memorySize: 2048, ephemeralStorageSize: Size.gibibytes(1), bundling: { // ①このプロパティを記載する nodeModules: [ "playwright-core", "@sparticuz/chromium", ] } }); const api = new aws_apigateway.RestApi(this, `apigateway`, { restApiName: `apigateway`, binaryMediaTypes: ["image/png"], // ②バイナリを返却する場合はここをきちんと記載 defaultCorsPreflightOptions: { allowOrigins: Cors.ALL_ORIGINS, allowMethods: Cors.ALL_METHODS, allowHeaders: Cors.DEFAULT_HEADERS, statusCode: 200, }, }); const nodeFunctionApi = api.root.addResource(`ss`); nodeFunctionApi.addMethod("POST", new aws_apigateway.LambdaIntegration( nodeFunction )); } }
①に依存するモジュールをを書かないとうまくいかない。/tmp/chromium
にchromeが存在しないというエラーが発生する。
②バイナリデータを返したい場合はbinaryMediaTypes
にMIMEを記述する。
バイナリデータ返却についてはこちらの記事も参考にしてみてほしい。
handlerの書き方
import type { APIGatewayProxyEvent } from "aws-lambda"; import { chromium } from "playwright-core"; import awsChromium from "@sparticuz/chromium"; let browser: Browser | null = null; export const handler = async (event: APIGatewayProxyEvent) => { if (!browser) { browser = await chromium.launch({ headless: true, chromiumSandbox: false, executablePath: await awsChromium.executablePath(), args: awsChromium.args, }); // 以下の処理 } });
@sparticuz/chromium
はnode_modulesディレクトリにchromiumを置くモジュールで、そのPathをPromiseで持っている。Playwrightはchromiumのパスを指定することが出来るので、そのPromiseで受け取って指定してあげればよい。