Lambdaのhandler外(メソッド以外)のコードは「コールドスタート時の1回だけ実行される」という話

Lambdaのhandler外に書いたコードは、Lambdaの仕組み的にコールドスタート時の1回だけ実行されます。 そのため、何気なく使用していると、思わぬ不具合の原因になるため、注意が必要です。
2019.09.27

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Lambdaのhandler外に、ライブラリの初期化コードなどを書く場合があります。

普段、何気なく書いていますが、Lambdaの仕組み的にhandler外(メソッド以外)のコードはコールドスタート時の1回だけ実行されます。 そのため、「現在時刻を変数に初期設定したとき、意図的に更新しない限り、Lambdaが複数回実行されても同じ時刻を指す」という状態になったりします。

注意:同じLambda環境の場合です。新しいLambda環境で実行される場合(スケールアウト、コード変更、時間経過など)は、それぞれのLambda環境で1回目と2回目以降で同様です。

実際に試してみました。

最初に結論

弊社岩田の資料より

下記の発表資料が超わかりやすいです!(他の内容もタメになるのでおすすめです!)

AWSドキュメントより

Lambda 関数内の宣言 (handler コード以外は、「プログラミングモデル」を参照) は、関数が再度呼び出された際に追加で最適化されない限り、初期化状態を維持します。

AWS Lambda 実行コンテキスト - AWS Lambda

やってみた

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

参考