花粉.
Table of Contents
AWS Lambda Function URLs
AWS Lambda Function URLsがリリースされました!!
今まではLambdaを使ってHTTPのエンドポイントを作る際はAmazon API Gatewayと組み合わせて作るかアプリケーションロードバランサー(ALB)のターゲットにAWS Lambdaを選ぶかいずれかが必要でした。
今回のアップデートでAWS Lambdaサービスの組み込み機能として、HTTPSエンドポイントをLambda単体で作成できるのでLambdaでAPIを作ったりWebhookの連携先として機能させる際にAPI Gatewayなどをかませる必要がなくなり便利かと思います。
使ってみる
使い方は超簡単でLambdaを作る際に関数を作る際に関数URLを有効化にしてあげるだけです。
後々の検証のため次のようなコードをデプロイしてみます。
async function sleep(time) {
return new Promise((resolve, _reject) => {
setTimeout(resolve, time);
});
}
exports.handler = async (event) => {
console.log(event);
let sleepTime = 0;
if (event.queryStringParameters !== undefined && event.queryStringParameters.sleep !== undefined) {
sleepTime = Number(event.queryStringParameters.sleep);
}
const response = {
statusCode: 200,
body: JSON.stringify(`Hello from Lambda and sleep ${sleepTime}!!!`),
};
await sleep(sleepTime);
return response;
};
デプロイできると関数URLが発行されます。
https://{url-id}.lambda-url-region.on.awsという不思議なTLDのURLができました。
こちらにアクセスしてみると、
確かにちゃんと関数が実行されてレスポンスが返ってきました!
また、handlerの引数で取得するeventの中身も、
{
version: '2.0',
routeKey: '$default',
rawPath: '/',
rawQueryString: '',
headers: {
'sec-fetch-mode': 'navigate',
'sec-fetch-site': 'none',
'accept-language': 'ja',
'x-forwarded-proto': 'https',
'x-forwarded-port': '443',
dnt: '1',
'x-forwarded-for': 'xxx.xxx.xxx.xxx',
'sec-fetch-user': '?1',
accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
'sec-ch-ua': '" Not A;Brand";v="99", "Chromium";v="100", "Google Chrome";v="100"',
'sec-ch-ua-mobile': '?0',
'x-amzn-trace-id': 'Root=1-62510b5b-xxxxxxxxxxxxxxxxxxxx',
'sec-ch-ua-platform': '"Windows"',
host: 'xxxxxxxxxxxxxxxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws',
'upgrade-insecure-requests': '1',
'accept-encoding': 'gzip, deflate, br',
'sec-fetch-dest': 'document',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36'
},
requestContext: {
accountId: 'anonymous',
apiId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
domainName: 'xxxxxxxxxxxxxxxxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws',
domainPrefix: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
http: {
method: 'GET',
path: '/',
protocol: 'HTTP/1.1',
sourceIp: 'xxx.xxx.xxx.xxx',
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36'
},
requestId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
routeKey: '$default',
stage: '$default',
time: '09/Apr/2022:04:28:11 +0000',
timeEpoch: 1649478491452
},
isBase64Encoded: false
}
みたいな感じでAPI Gatewayのイベント形式とよく似てます。
なので、API Gatewayで動かしていたLambdaの置き換え、みたいなこともそこまで苦労しないかもしれませんね。
確かに便利ではありますが...
実際API Gatewayと組み合わせる構成と比べて、リソースを作るのが楽、以外何がうれしいの?という気はしますのでもう少しDeep Diveしてみたいと思います。
認証
認証的な設定は今のところAWS IAM認証がまずサポートされてます。
クレデンシャルとかから署名バージョン4を作成してアクセス時にして認証させる方法です。
独自のオーソライザーが挟めないので、あくまでも同じアカウントにアクセスできる開発者向けのAPIとして使うのがよさそうです。もっと込み入ったことがやりたいならAPI Gatewayをおとなしく使いましょう...。(もうちょっと色々試してみます。)
IAM認証を設定したうえで、署名を付けず未認証の状態でアクセスすると、
{"Message":"Forbidden"}
が返ってきました。
タイムアウト
いよいよ本題です。API GatewayとLambdaの組み合わせを使っているとよく困る話がAPI Gatewayのタイムアウトだと思ってます。
Lambdaのタイムアウトは15分まで拡張されてますが、API Gatewayの最大統合タイムアウトは30秒でそれをクオータで引き上げることもできないのでAPI Gateway + Lambdaの構成の際はどう頑張ってもAPIが30秒でタイムアウトしないような設計が求められます。
確かにHTTPで30秒以上かかるようなAPIは非同期APIにして完了をポーリングさせたり、pushさせたりしたほうが正しい設計だと思いますが思いのほか30秒タイムアウトが厳しい...。という経験は多いのではないでしょうか?
この記事を見たとき私はLambdaにURLエンドポイントがビルトインされるならタイムアウトはLambdanのそれになるのでは?と思いました。実験してみます。
さきほどデプロイしたコードをもう一度見てみましょう。
async function sleep(time) {
return new Promise((resolve, _reject) => {
setTimeout(resolve, time);
});
}
exports.handler = async (event) => {
console.log(event);
let sleepTime = 0;
if (event.queryStringParameters !== undefined && event.queryStringParameters.sleep !== undefined) {
sleepTime = Number(event.queryStringParameters.sleep);
}
const response = {
statusCode: 200,
body: JSON.stringify(`Hello from Lambda and sleep ${sleepTime}!!!`),
};
await sleep(sleepTime);
return response;
};
returnの手前でsleep(setTimeout)を入れてます。そしてクエリパラメーターでsleepのミリ秒を指定できるようにしてます。
まず、何も設定しないときはsleepはしないのですぐレスポンスが返ってきます。
sleepを1000にすれば1秒待ってレスポンスが返ってきます。
では、API Gatewayのタイムアウトの30秒に設定してみましょう。(Lambdaのタイムアウトは2分にしてます)
タイムアウトしませんでした!!ではLambdaのタイムアウトまで引き延ばしてみましょう!
Internal Server Errorしました。これは直感的でいいですね。
結論
Lambdaライフを楽しみましょう!