Lambda Web FunctionsでHTTP serverを動かしてみる
東京regionでLambda Web Functionsを検証しました。同じ環境での並行処理、HTTP streaming、429とtimeoutを、実測とログから追います。
Series: Try Lambda Web Functions (4 articles)
- 1Lambda Web FunctionsでHTTP serverを動かしてみる This article
HTTP serverを動かしてみる
Lambda Web Functionsでは、同じHTTP serverで複数のrequestを処理できました。今回の検証では、500msの非同期待ちは同じ環境で2件重なりました。一方、同期CPU処理は同じ環境で順番に進みました。
環境の起動や台数の調整をAWSへ任せ、HTTP serverを動かしたい場面が対象です。Web Functionsでは、HTTPS終端と実行環境の管理をLambdaが担います。同じprocessのrequestをどう分けるかは、アプリ側の設計に残ります。東京regionで、非同期待ち、streaming、失敗時の扱いを確かめました。
2026年10月12日の発表 で、従来のLambda関数にはLambda Event Functionsという名前が付きました。既存関数のコード変更やredeployは不要です。Web Functionsは、HTTPの待ち受けを行う別の実行モデルです。
検証時の構成
同じZIPから2つのrevisionを作りました。revisionは、コードと設定を固定したversionです。変えたのは、1環境あたりのrequest数の上限です。1と8を、それぞれ別のendpointへ割り当てました。

検証時の構成です。青はHTTPの往復、紫はログ、破線はS3からのコードの読み込みを示します。
項目 | 条件 |
|---|---|
region | ap-northeast-1 |
runtime | nodejs24.x、実際のNode.jsはv24.21.0 |
architecture | Arm64 |
endpoint | HomeRegion、IamAuth |
maxConcurrencyPerEnvironment | 1 / 8 |
maxEnvironments | 各endpointで2 |
rateLimit | 各endpointで100 RPS |
timeoutSeconds | 両revisionとも3秒 |
Web Functionsの 対応runtime は、今回の確認時点では正式対応のNode.js 24でした。実行環境は、serverのprocessが動く単位です。maxEnvironmentsの下限は2です。1環境へ固定する実験にはせず、同じprocessの処理を追いました。環境IDはserver起動時に生成したUUIDです。Lambdaが付けるrequest IDと合わせて、ログと応答を照合しました。
resourceはCDKで作成しました。コード用S3 bucketはversioningを有効にし、同じobject versionを両revisionへ指定しました。呼び出しにはSigV4、AWSの署名方式を使いました。 IAM認証の要求 に合わせ、service名をlambdaとし、payload hashも付けています。
HTTPの待ち受け
Lambda用handlerへHTTP eventを変換するadapterは使いませんでした。Node.js標準のnode:httpでserverを起動しています。起動部分は次のコードです。
JavaScript
const address = process.env.AWS_LAMBDA_HTTP_ENDPOINT ?? "127.0.0.1:3000";const separator = address.lastIndexOf(":");const host = address.slice(0, separator).replace(/^\[|\]$/g, "");const port = Number(address.slice(separator + 1));server.listen(port, host);
serverには、500msの待ち、100msのCPU処理、250ms間隔のstreamingを選ぶrouteを用意しました。署名したrequestのpathとqueryは次の形です。
text
GET /work?kind=wait&ms=500&trace=wait_sampleGET /work?kind=cpu&ms=100&trace=cpu_sampleGET /stream?mode=stream&ms=250&count=4&trace=stream_sampleGET /stream?mode=buffered&ms=250&count=4&trace=buffered_sample
AWS_LAMBDA_HTTP_ENDPOINTは、Lambdaが指定する待ち受け先です。Web Functionsでは、そのhostとportへbindします。外側のHTTPSをLambdaが終端し、serverへHTTP requestを渡します。
GETではqueryのsample=helloを読み取れました。POSTのbodyには、送ったJSON文字列が残りました。不正な待ち時間を渡すと、アプリの入力検査がHTTP 400を返しました。HTTPのmethodやbodyを、通常のrequest objectから読む形です。
同じ環境の並行処理
非同期待ちでは、上限8のほうが上限1より多くのrequestを処理できました。healthで動作を確認し、上限8では2・4・8件の待ち処理でwarm-upしました。その後、8件を並行に送り、各条件を2回試した結果です。
処理 | 1環境の設定上限 | 送信 | HTTP 200 | HTTP 429 | 同じ環境で観測した最大の重なり |
|---|---|---|---|---|---|
非同期待ち500ms | 1 | 16 | 4 | 12 | 1 |
非同期待ち500ms | 8 | 16 | 8 | 8 | 2 |
同期CPU処理100ms | 8 | 16 | 8 | 8 | 1 |
待ちは、外部DBへ接続せず、Promiseのtimerで作りました。CPU処理は、main threadを100ms占有するloopです。速さの優劣を比べる入力ではなく、同じprocessで処理が重なる条件を分けています。
JavaScript
// 非同期待ちawait delay(ms, undefined, { signal: controller.signal });// main threadを占有するCPU処理const deadline = performance.now() + ms;while (performance.now() < deadline) {// 指定した時間だけevent loopを塞ぐ}

processedはserver側で処理を終えた件数、maxActiveは同じprocessで観測した最大の重なりです。testは処理条件、environmentsは起動時UUIDで区別したprocess数です。拒否されたrequestはserverへ届かず、この集計には入りません。HTTP 429の件数はclient側の応答から数えました。
上限8は、常に8件を同時処理する設定ではありません。 scalingの仕様 では、Lambdaがresource使用量に応じて環境内の並行数を調整します。今回の2件を、その動的な上限の値とは確認できていません。429のerror headerは、すべてPlatform.EndpointMaxEnvThrottleでした。環境数を2に絞った条件での結果です。
CPU処理では、同じ環境の2つのcallbackが順番に始まりました。clientの成功応答は、各環境の1件目が約173〜177ms、2件目が約269〜277msでした。Node.jsのevent loop、処理を進める仕組みを同期処理が塞ぐと、後続のrequestも待ちます。worker threadsなどへCPU処理を分ける案は、今回の実測範囲には含めていません。
HTTP streaming
serverが生成したJSONを順に返すと、最初の1行は約0.33秒で届きました。4行を保持してから返すbuffered応答では、約1.08秒後にまとめて届きました。
250msごとにJSONを1行作り、4行返しています。ここでは1行を1chunkとして記録しました。clientはTLS接続を始める直前から、各行を読み終えるまでを測っています。
mode | 試行 | chunk 1 | chunk 2 | chunk 3 | chunk 4 |
|---|---|---|---|---|---|
stream | 1 | 328.7ms | 579.0ms | 829.7ms | 1080.7ms |
stream | 2 | 326.4ms | 576.6ms | 827.7ms | 1078.5ms |
buffered | 1 | 1080.2ms | 1080.2ms | 1080.2ms | 1080.3ms |
buffered | 2 | 1088.0ms | 1088.1ms | 1088.1ms | 1088.1ms |
streamではresponse.writeを各回に呼びます。bufferedでは配列に保持し、最後にresponse.endへ渡しました。実測コードの処理部分です。
JavaScript
const lines = [];response.writeHead(200, { "content-type": "application/x-ndjson" });for (let index = 1; index <= count; index++) {await delay(intervalMs, undefined, { signal: controller.signal });const line = `${JSON.stringify({ ...details(), index })}\n`;if (mode === "stream") response.write(line);else lines.push(line);}response.end(mode === "buffered" ? lines.join("") : undefined);

これはserver側のログです。written=1が各chunkを書き込んだ行です。written=0は最後まで保持した行です。request IDをclientの応答と照合しました。画像のelapsedMsはserver内の経過時間で、上の表はclientの受信時間です。
生成に約1秒かかる処理でも、途中の結果を先に渡せました。実際のAI推論やDB接続は試していません。先にJSONを届ける経路を、標準HTTPの処理で確かめた結果です。
失敗とtimeout
HTTP 500を返すrouteへ、同じtraceを付けて2回送りました。両方とも500でした。request IDは別々になり、serverのログにも2回の実行が残りました。その後のhealth要求は200でした。これを2組試しています。

ordinalは、各processが受けたrequestの通し番号です。今回の2組では、再送は別のprocessへ届きました。
clientに自動retryは入れていません。ここで行ったのは、明示した2回の送信です。再送を設計するときは、業務処理の重複を防ぐIDと、その処理の完了条件をアプリ側で持ちます。
次に、5秒待つ要求を3秒のtimeoutへ送ると、2回ともHTTP 504になりました。error headerはRuntime.RequestTimeoutでした。clientの全体時間は3075.4msと3082.8msです。その後のhealth要求はいずれも200でした。

serverでは接続のcloseを監視し、AbortControllerで待っていたtimerを中断しました。今回の副作用はtimerだけです。timeoutになった業務処理をどう確定し、外部への書き込みをどう扱うかは、別に設計する必要があります。
まとめ
非同期の待ちが多いNode.jsのHTTP serverでは、同じ環境でrequestを重ねて処理できました。streamingも、標準のresponse.writeで途中のJSONを届けられました。
その分、requestごとの状態を分け、同期CPU処理の占有を抑える設計が要ります。設定した上限と実際の重なり、429、timeoutを一緒に見て、依存先へ通す量を決めます。
公式の 用途の分け方 では、HTTPの処理にWeb Functions、queue messageやfile uploadの処理にEvent Functionsを案内しています。今回の実測は、HTTPを入口にした条件に限ります。
Series: Try Lambda Web Functions (4 articles)
- 1Lambda Web FunctionsでHTTP serverを動かしてみる This article
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article