この記事は公開されてから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上で動作確認しない限り、見つかりにくい動作だと思います。 どなたかの参考になれば幸いです。