まえがき
前回のLambda エフェメラルストレージのアップデートに引き続き、今度はAPIGateway無くてもAPI経由でLambdaが起動できるようになりました。(2022.4.5)
このアップデートによりWebhookの接続先を直接指定できたり、ExpressやFlaskなどのバックエンドframeworkをLambda上に立て、Proxyさせるなどが簡単にできるようになります。
今までもAPIGatewayのProxy機能を利用したり、ALBからLambdaを呼び出すことも可能ではありましたが、よりシンプルにできるにようになりました。
概要
既にServerlessFrameworkでも対応されているのですが、ServerlessFrameworkのブログに、それぞれの役割が載っており、とても分かりやすかったです。
AWS Lambda Function URLs with Serverless Framework 抜粋
特にMaximum HTTP response timeoutのレスポンス29秒タイムアウトの制限がなく、いとのことで調べてみようと思います。
設定
マネージメントコンソール上の「設定」から「一般設定」に「関数 URL - 新規」の項目が増えており、
こちらから作成すること可能ですが、既にServerless frameworkで対応されていましたので、こちらからデプロイしてみたいと思います。
※「LambdaFunctionsUrls」の機能を使用するにはServerless framework 3.12.0以上を使用する必要があります。
まずはserverless projectを作成します。
# serverless framework version up
$ npm install -g serverless
52 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
$ serverless --version
Framework Core: 3.12.0
Plugin: 6.2.1
SDK: 4.3.2
$ serverless create --template aws-python3 --path LambdaFunctionUrlTest
✔ Project successfully created in "LambdaFunctionUrlTest" from "aws-python3" template (5s)
cd LambdaFunctionUrlTest
つぎにserverless.ymlを開き、urlsを追加します
functions:
hello:
handler: handler.hello
url: true # 追加
IAM認証を使用する場合は以下のように修正します
url:
authorizer: aws_iam
デフォルトではCROSが許可されていません。許可する場合は以下のように修正します
url:
# Configure CORS in details:
cors:
allowCredentials: …
allowedHeaders: …
allowedMethods: …
allowedOrigins: …
exposedResponseHeaders: …
maxAge: ….
デプロイをします
デプロイ完了するとendpoint urlが表示されます
(外部公開されてしまうため、ダミーのURLを載せています)
$ serverless deploy
Deploying LambdaFunctionUrlsTest to stage dev (ap-northeast-1)
✔ Service deployed to stack LambdaFunctionUrlsTest-dev (49s)
endpoint: https://xxxxxxxxxxxxxxxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws/
functions:
hello: LambdaFunctionUrlsTest-dev-hello (389 B)
マネージメントコンソールから「Lambda」 -> 「一般タブ」 -> 「関数 URL - 新規」から関数URLを確認できます。
次にAPIをcurlから実行してみます。
curl -X POST https://xxxxxxxxxxxxxxxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws/test
{
"message": "Go Serverless v1.0! Your function executed successfully!",
"input": {
"version": "2.0",
"routeKey": "$default",
"rawPath": "/test",
"rawQueryString": "",
"headers": {
"x-amzn-trace-id": "Root=1-624f6177-1a0368a27e5fa2960e347431",
"x-forwarded-proto": "https",
"host": "xxxxxxxxxxxxxxxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws",
"x-forwarded-port": "443",
"x-forwarded-for": "240d:1a:6b8:1000:f440:a4c9:405:953c",
"accept": "*/*",
"user-agent": "curl/7.77.0"
},
"requestContext": {
"accountId": "anonymous",
"apiId": "xxxxxxxxxxxxxxxxxxxxxxxxx",
"domainName": "xxxxxxxxxxxxxxxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws",
"domainPrefix": "jnizrnojzkxxevhncd3cwz5ode0leyol",
"http": {
"method": "POST",
"path": "/test",
"protocol": "HTTP/1.1",
"sourceIp": "240d:1a:6b8:1000:f440:a4c9:405:953c",
"userAgent": "curl/7.77.0"
},
"requestId": "823d3d28-62b8-4302-b2e9-5c0ef17385d7",
"routeKey": "$default",
"stage": "$default",
"time": "07/Apr/2022:22:11:03 +0000",
"timeEpoch": 1649369463756
},
"isBase64Encoded": false
}
リクエストのpathはlambdaのパラメータのhttp.path
、methodはhttp.method
に割り当たることが確認できました。
検証
handler.pyにsleep(60)を追加し、再度APIを実行してみます。
$ curl -so /dev/nul -w "time_total: %{time_total}\n" https://xxxxxxxxxxxxxxxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws/test
time_total: 60.530532
29秒を超えてもエラーにならないことが確認できました。
一応sleep(899)に変更し15分ギリギリのリクエストも試してみます。
curl -so /dev/nul -w "time_total: %{time_total}\n" https://xxxxxxxxxxxxxxxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws/test
time_total: 1737.450523
time_totalがおかしいですが、リクエスト中放置した際にPCがスリープされた時間も含まれているようです。CloudWatch Logs上で確認します。問題なくレスポンスが返ってきています。
次にLambdaのタイムアウトを超えた場合に、どのようなエラーが返ってくるか確認します。
$ curl -so /dev/nul -w "time_total: %{time_total}\n" https://xxxxxxxxxxxxxxxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws/test
< HTTP/1.1 502 Bad Gateway
< Date: Sat, 09 Apr 2022 22:44:51 GMT
< Content-Type: application/json
< Content-Length: 21
< Connection: keep-alive
< x-amzn-RequestId: 18337225-5086-4559-ae1b-8c0eabba9b2c
< X-Amzn-Trace-Id: root=1-62520c27-0d32bdbb64658b1d19185c0b;sampled=0
<
Internal Server Error
status codeは502 Bad Gatewayが返ってくることが確認できました。
メッセージはInternal Server Error
となっていることに注意です。
まとめ
LambdaFunctionURLsを使うことで、29秒超えのリクエストが追加費用が必要なく簡単にできるようになりました。
いままでAPIGatewayの29秒制限によりに同期的なAPIを非同期に変更した場合など、アーキテクチャを変更せずURLsを発行して一時的に回避するなどができそうです。
次はbackend frameworkを利用してLambda Function URLsの機能を実装してみたいと思います。