API Gatewayと連携してるLambdaを放置すると突然エラーになる話

API Gatewayと連携してるLambdaを放置すると突然エラーになる話 データエンジニア兼バックエンドエンジニアの @kazasiki です。

今日は表題の通り、AWSのAPI Gateway + Lambdaでハマった件について書きます。

先日、API Gateway + Lambda の構成でAPIを提供しているサービスで突然500エラーが発生してちょっとしたトラブルになりました。

Lambdaのログを確認すると、それらしいものはなく、そもそもAPIのパスに対応するFunctionがinvokeされた痕跡すらありません。

次にAPI GatewayのログのLambdaを呼び出してる部分を見てみるとそれらしいエラーがありました。 エラーメッセージは CodeArtifactUserPendingException でした。

CodeArtifactUserPendingException とは

まずはAWSの公式ドキュメントの方を探してみます。エラーメッセージが該当するのは以下です。

docs.aws.amazon.com

Issue: CodeArtifactUserPendingException error message
The CodeArtifact is pending optimization. The function transitions to active state when Lambda completes the optimization. HTTP response code 500.

下の行を雑に訳すと、 CodeArtifactは最適化待ちです。Lambdaの最適化が終わると、このFunctionはアクティブになります。 という感じです。

このメッセージについて理解するには、Lambda + container images の挙動について理解する必要があります。

該当するドキュメントはこの辺りです。

docs.aws.amazon.com

After you upload a new or updated container image, Lambda optimizes the image before the function can process invocations. The optimization process can take a few seconds. The function remains in the Pending state until the process completes. The function then transitions to the Active state. While the state is Pending, you can invoke the function, but other operations on the function fail. Invocations that occur while an image update is in progress run the code from the previous image.

雑に訳すと、 container imageをアップロードすると、Lambdaはimageを最適化します。この処理には数秒かかることがあり、完了するまでFunctionはPending状態になります。その後、FunctionはActive状態になります。 という感じです。

で、さっき出てた CodeArtifactUserPendingException はまさに Pending状態だからちょっと待ってくれ というエラーなわけです。ただ、今回のエラーが起きる直前にイメージの更新はしてません。なので、当時このエラーメッセージを読んでの感想は「そもそもなんでPending状態になっているのか?」というものでした。

Pending状態になっていた理由

実はさっき参照したFunction Lifecycleのドキュメントにそのまんまの記述があります。

If a function is not invoked for multiple weeks, Lambda reclaims its optimized version, and the function transitions to the Inactive state. To reactivate the function, you must invoke it. Lambda rejects the first invocation and the function enters the Pending state until Lambda re-optimizes the image. The function then returns to the Active state.

重要なところなのでちょっと丁寧に訳すと、

Functionを数週間起動しないと、Lambdaは最適化されたバージョンを再要求し、Inactive状態に移行します。Functionを再Active化するには、Functionをinvokeする必要があります。Lambda は最初のinvokeを拒否し、Lambda がimageを再最適化するまで、このFunctionはPending状態になります。

という感じです。

今回自分がハマったのは正にこれでした。本番環境での動作確認や負荷試験をしてから実際にサービスが開始するまでかなり間がありました。主にプロモーションの都合ですが、3週間ほど間があったはずで、その間にFunctionがInactiveになったというオチでした。

エラーの回避策について

その後、ドキュメントにバッチリ書いてあるとはいえ挙動が独特で不安だったので、念の為AWSの技術サポートの方にも連絡して「こういう認識であってます?」みたいなやり取りをしました。

結果としてはエラーの原因に対する認識はあっていて、回避策としては「1週間に1回で良いので該当のFunctionを定期的にinvokeすることでエラーを回避できます」と言われたので、そのとおりに実装して一旦は解決しました。逆に言うと、解決策はそれくらいしかないようです。

そもそもAPIが数週間放置されるということは普通ないので、特に対策をしてなくても二度とエラーは起こらない可能性もありますが、500エラーになる可能性を放置するわけにもいかないのできちんと対策をしました。

やったことは単純でLambda FunctionをEvent Bridgeから定期的にinvokeするだけです。Invoke出来れば良いので、API Gatewayを経由する必要はありません。

中で実行するコードによっては「なにもしない」という分岐を明示的に作って、分岐判定用のパラメタを渡したりする必要があります。また、状態の管理はFunction単位で行われるため、複数のFunctionを定義している場合は全てのFunctionに回避策を適用する必要があります。

APIの外形監視で防げたのでは?という疑問もあるかもしれませんが、APIのパスによってもろもろ要件が違うのもあってFunctionを複数定義してたので、どっちみち死んでました。少なくとも私の感覚では、Functionごとに外形監視する必要はないと思います。

所感

自分がしっかりドキュメントを読んでなかったのが悪いんですが、この仕様はかなり罠っぽい挙動だと思っていて、そもそも 数週間の間invokeされなかったら自動的にinactiveになって初回invokeは必ず失敗する という挙動は果たして運用的に許容できるのだろうか、と思います。

今回エラーとなったAPIはブラウザから叩かれる(ユーザが直接結果を見る)ものですし、一発でアラートとして対応しましたが、バックエンドから呼び出すAPIであれば、普通に数秒おいてリトライして成功するという流れに出来るのかもしれません。今どきはブラウザからAPIを叩く場合も500エラーになったら数秒置いてリトライをするのが普通なんでしょうか。フロントエンド詳しくないマン。

とはいえ、Lambdaの実行環境のことを考えると、全然invokeされないcontainer imageを半永久的に保持しつづけるのも現実的ではないと思っていて、数週間invokeがなければ破棄したいというのも妥当な仕様なように思います。本当にそんな感じの挙動になっているかはわかりませんが。。。

ちなみに、API Gateway + Lambdaでよく話題になるCold Startについては、今回の問題とは関係ありません。Cold Startについては数秒待たせる程度でレスポンスが返せることを確認していました。この場合は少なくとも500エラーにはならないので、特に問題になりません。あまり待たせる時間が長いとAPI Gatewayの方でタイムアウトしてしまいますが、それは実行するイメージ次第ですね。

というわけで、Lambdaの罠っぽい話でした。これを読んだ方で API Gateway + Lambda (container image) を本番に導入してる方は、きちんとinactive対策ができてるか確認してみてはいかがでしょうか。

alt

@kazasiki

デジタルテクノロジー統括部 デジタルソリューション部 Webアプリエンジニアグループ リードエンジニア

バックエンドエンジニア。VRゲームとダンスミュージックが好き。都内のクラブによく行く。

※2022年6月現在の情報です。