AWS Lambda終了時にHTTP接続が終了していなかった場合

以前AWS LambdaからDB接続をした際接続の終了をawaitで待機しなかったことでLambdaが終了してもDB接続のコネクションが残り続けるバグを出したことがあった。
それと同じように、AWS Lambda内でHTTP接続を行い、そのレスポンスが返ってくる前にLambdaが終了した場合どうなるのかを確認した。

接続先のコード

<?php

// 現在の時刻
echo date('h:i:s') . "\n";

// 10 秒間遅延させる
sleep(10);

// 再開!
echo date('h:i:s') . "\n";

?>

PHPの公式からそのまま拾ってきたコード。実行に必ず10秒以上かかるコードを使用して、Lambdaの挙動を確認する。

awaitを使用した場合

'use strict';

const axios = require('axios');

module.exports.hello = async event => {
  const response = await axios.get("http://xxx.xxx.xxx.xxx/");
  console.log(response);
};

まずは比較のためHTTP接続のレスポンスを待機した場合を確認した。上記PHPを接続先として実行したため、Lambdaのタイムアウト時間が10秒未満であればタイムアウトが発生し、処理が中断された。サーバー側での接続もnetstatコマンドで確認したが、タイムアウトになった時点でESTABLISHED->CLOSE_WAITに移行し、そのまま接続が終了した。 逆にタイムアウト時間を10秒以上にすると処理は成功し、サーバー側の接続もTIME_WAITに移行して一定時間後にそのまま終了となった。

Promiseを使用した場合

'use strict';

const axios = require('axios');

module.exports.hello = async event => {
  axios.get("http://xxx.xxx.xxx.xxx/")
    .then(response => {console.log(response)})
    .catch(e => {console.error(e, e.stack)});
};

レスポンスが返ってくれば表示させるが、レスポンスが返ってくるまで処理を待機しないコード。これを実行するとLambda自体はすぐ終了する(正常終了扱い)が、HTTP接続のレスポンスは表示されない。サーバー側はLambdaが終了しても一定時間ESTABLISHEDのままだが、その後FIN_WAIT2に移行し、そのまま接続が終了した。仕様ではFIN_WAIT2からTIME_WAITに移行するはずだが、一瞬だったのか異常終了扱いなのかTIME_WAITに変化する瞬間を確認できなかった。

まとめ

Lambda終了時にHTTP接続が終了していなかった場合Lambdaが終了してもサーバー側との接続は一定時間継続していた。その後レスポンスが返ってきてもそれが表示されることはなく、サーバー側の接続も終了した。
一応接続自体は一定時間後に終了するようなので、わざわざレスポンスを待たなくていいようなリクエストを投げる場合はawaitで待機しなくてもいいのかもしれない。