Lambdaのhandler外(メソッド以外)のコードは「コールドスタート時の1回だけ実行される」という話
Lambdaのhandler外に、ライブラリの初期化コードなどを書く場合があります。
普段、何気なく書いていますが、Lambdaの仕組み的にhandler外(メソッド以外)のコードはコールドスタート時の1回だけ実行されます。 そのため、「現在時刻を変数に初期設定したとき、意図的に更新しない限り、Lambdaが複数回実行されても同じ時刻を指す」という状態になったりします。
注意:同じLambda環境の場合です。新しいLambda環境で実行される場合(スケールアウト、コード変更、時間経過など)は、それぞれのLambda環境で1回目と2回目以降で同様です。
実際に試してみました。
最初に結論
弊社岩田の資料より
下記の発表資料が超わかりやすいです!(他の内容もタメになるのでおすすめです!)
AWSドキュメントより
Lambda 関数内の宣言 (handler コード以外は、「プログラミングモデル」を参照) は、関数が再度呼び出された際に追加で最適化されない限り、初期化状態を維持します。
やってみた
lambdaの用意
下記のLambda関数を用意します。
from datetime import datetime # これは初回のみ実行される(2回目以降、タイムスタンプは変わらない) current_time_outside_handler = datetime.now() def lambda_handler(event, context): # これは毎回実行される(2回目以降、タイムスタンプは変わる) current_time_inside_handler = datetime.now() print(f'current_time_outside_handler: {current_time_outside_handler}') print(f'current_time_inside_handler : {current_time_inside_handler}')
実行してみる
上記のLambdaを手動実行させると、下記となりました。
current_time_outside_handler
:変数は更新されていないcurrent_time_inside_handler
:変数は更新されている
1回目
current_time_outside_handler: 2019-09-27 15:38:39.293918 current_time_inside_handler : 2019-09-27 15:38:39.295886
2回目
current_time_outside_handler: 2019-09-27 15:38:39.293918 current_time_inside_handler : 2019-09-27 15:39:15.214256
3回目
current_time_outside_handler: 2019-09-27 15:38:39.293918 current_time_inside_handler : 2019-09-27 15:46:54.519712
4回目
current_time_outside_handler: 2019-09-27 15:38:39.293918 current_time_inside_handler : 2019-09-27 15:53:38.080167
活用?の例
この動作を活用すると、handler外でSDKの初期化等を行えば、Lambda実行時に少しは効率的になりますね。(速度面)
import boto3 # この処理と変数の値は使いまわしても問題なし dynamodb = boto3.resource('dynamodb') def lambda_handler(event, context): table = dynamodb.Table('use-table-name') # 以下略
さいごに
タイムスタンプを例に取り上げましたが、何らかのフラグや状態などの変数をhandler外で定義すると、同じことが発生します。 Lambdaのコードは、ステートレスになるように書くことが大切ですね。(改めて)
実際のLambda上で動作確認しない限り、見つかりにくい動作だと思います。 どなたかの参考になれば幸いです。