AWS LambdaでAPIを作成したときのことです。ハンドラー外で実装したグローバル変数初期化が実行されずにハマったことがあるので注意喚起を込めて記事にします。
先に結論 Lambdaのグローバル変数は呼び出し間で共有される
- Lambda関数のグローバル領域(ハンドラー外)に動的な処理は書かない方が良い
- グローバル領域(ハンドラー外)に何か書くときは以下の点を意識する
- コールドスタート時はグローバル領域(ハンドラー外)の処理が実行される
- ウォームスタート時はグローバル領域(ハンドラー外)の処理が実行されない
図にするとこんな感じです。
発生した事象 呼出しごとにグローバル変数の初期化が実行されない
以下、もちろんハンドラー関数はlambda_handlerです。
import datetime
dt_now = datetime.datetime.now()
def lambda_handler(event, context):
return {"dt_now":str(dt_now)}
何回も実行してもdt_nowが更新されませんでした。
原因 Lambdaはウォームスタート時にグローバル変数は呼び出し間で共有される仕様である
ウォームスタート時はpyファイル冒頭の処理(グローバル変数初期化)は実行されないようでした。ハンドラー関数からの実行です。
一方でコールドスタート時はpyファイル冒頭のグローバル変数の初期化から実行されるようでした。
AWS公式ブログをあさっていたら当事象に対する見解が記載されていました。
当事象は呼び出し間でのグローバル変数のリークと呼ばれるようです。
グローバル変数は、呼び出しごとのコンテキスト固有の情報の格納先としては避けるべきです。1回の呼び出しの間だけ使用され、次の呼び出しでリセットされるグローバル変数を持つ関数の場合は、ハンドラのローカルな変数スコープを使用してください。これにより、呼び出し間でのグローバル変数のリークを防ぐだけでなく、静的初期化のパフォーマンスも向上します。
https://aws.amazon.com/jp/blogs/news/operating-lambda-performance-optimization-part-2/
教訓と対策
AWSブログに記載されている通り、
グローバル変数は、呼び出しごとのコンテキスト固有の情報の格納先としては避けるべき
です。
それによりグローバル変数リークによるバグの抑制に加え、初期化(コールドスタート)のパフォーマンス向上につながるようです。
システムエンジニア
AWSを中心としたクラウド案件に携わっています。
IoTシステムのバックエンド開発、Datadogを用いた監視開発など経験があります。
IT資格マニアでいろいろ取得しています。
AWS認定:SAP, DOP, SAA, DVA, SOA, CLF
Azure認定:AZ-104, AZ-300
ITIL Foundation
Oracle Master Bronze (DBA)
Oracle Master Silver (SQL)
Oracle Java Silver SE
■略歴
理系の大学院を卒業
IT企業に就職
AWSのシステム導入のプロジェクトを担当