⚙️

LambdaでWeb APIの結果がキャッシュされる問題

に公開

事象

AWS Lambda を使って、5分おきにとある Web API を叩いて情報を取得する処理を作ったんですが、なぜかAPI側では更新されているはずの情報が、Lambdaでは古いままという現象が発生しました。

結論

Lambda実行環境が使いまわされると、リクエストの結果がキャッシュされる(ようだ)。

背景

調べてみると、どうやらLambdaの実行環境の再利用が関係しているようでした。

Lambdaは関数が実行されるときにコンテナのような「実行環境」が立ち上がる仕組みになっていて、実行が終わってもその環境はしばらくの間は生き続けます。

そして次に関数が呼ばれたとき、その既存の環境を使いまわす(=ウォームスタート)場合と、新しく作る(=コールドスタート)場合があります。

このウォームスタート時、前回のHTTPリクエストの結果がキャッシュされて再利用されていたようです。
なので、API側で情報が更新されていても、Lambdaから見ると「前回と同じ古いデータ」に見えてしまっていたというわけです。

Lambdaの実行環境ってのは、ざっくり言えば仮想マシンの上に立ってる軽量なコンテナみたいなもので、処理が終わってもすぐには消えず、しばらく生き残っています。

この再利用される仕組みのおかげでウォームスタートはすごく高速なんですが、今回みたいにキャッシュが悪さをすると困ります。

ちなみに、コールドかウォームかは、処理時間を見ればだいたい分かります。ウォームスタートのほうが明らかに早い。

じゃあ毎回コールドスタートさせればいいじゃん、と思うところなんですが、これができない。

Lambdaの実行環境がどうなるかは、開発者側では制御できないんですよね。

一応、分かっている範囲の傾向としては、

  • 関数をデプロイすると必ずコールドスタートになる
  • 最後の実行から6分くらい空くとコールドスタートになるっぽい
    というものがあります。

でもこの「6分」というのもあくまで体感で、AWSが公式に明言しているわけではないので、いつ仕様が変わるかも分かりません。

今回のように「5分おきに実行」する場合、この6分ルールは微妙に噛み合いません。

対応

今回は苦肉の策として、同じ処理をするLambda関数を2つ作り、それぞれを5分ずらして交互に実行するという方法で回避することにしました。

これなら、片方が5分ごとにウォームスタートになったとしても、もう片方は6分以上空くのでコールドスタートになる可能性が高い、というロジックです。

なんか違うこと言ってたらご指摘頂けますと幸いです。

Discussion