20
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

lambda_handler外のグローバル変数に気をつけよう(datetime)

Last updated at Posted at 2019-12-20

はじめに

ジョブが作成されてからLambdaが実行されるまでの間の時間(滞留時間)を取得する
Lambdaを作成していた時に
現在日時を取得するためにdatetimeを使用していたのですが、
そこで「AWS Lambdaは関数インスタンスを再利用」というのに見事にハマったので、
記事にしてみたいと思います。

最初に作成していたコード

まずLambdaが実行された現在日時を取得するための
コードを簡略化したものが以下になります。

.py
from datetime import datetime

now = datetime.now()

def lambda_handler(event, context):
    method_a()

def method_a():
    method_b()

def method_b():
    method_c()

def method_c():
# xはジョブの作成日時を表しています。
   time = now - x
   print(data)
  • ジョブの作成時刻をx
  • 現在時刻をnow
  • 滞留時間をtime

として表しています。

時刻を表すnowをグローバル変数として宣言して
どのメソッドでも使えるようにしてました。

#ローカルでは成功したけど…
ローカルでは滞留時間を取得できたので、
そのままビルドデプロイしてLambdaを作成しました。
最初のLambdaのテストも成功して問題はありませんでした。

よし大丈夫だ!もう一回テストして確認しよう…

あれ!?滞留時間がおかしい!!!!!!

1回目で上手く取得できていた滞留時間が
2回目以降上手く取得できませんでした。

何回やってもtimeがおかしい。

そこでまたビルドデプロイして
Lambdaを更新させてみたところ上手くいきました。

しかし、また2回目以降はダメでした。

原因は

そこで原因調査のために色々調べていると
こちらの記事に出会いました!

ずばり原因は、lambda_handler外で宣言したグローバル変数のnowでした。

どうやらLambdaはパフォーマンス向上のために
関数のインスタンスを再利用するみたいです。

https://aws.amazon.com/jp/lambda/faqs/
image.png

つまり一回目に取得したnowの日時がキャッシュされ
2回目以降も同じ値が再利用されていたみたいです。

常にLambdaの関数インスタンスは新規で作成されているものだと
思っていたので、全く気づきませんでした!!

lambda_handler内にグローバルに変数を置きたい

原因を理解したところで
とりあえずnowlambda_handler内に置きました。
これでLambdaが実行されるたびに新しくnowの日時を取得してきてくれます。

.py
from datetime import datetime

def lambda_handler(event, context):
    now = datetime.now()
    method_a(now)

def method_a(now):
    method_b(now)

def method_b(now):
    method_c(now)

def method_c(now):
# xはジョブの作成日時を表しています。
   time = now - x
   print(data)

この形でも実行できるのですが、
こんなにメソッドを経由して渡すのはかっこ悪いので
以下のように修正しました。

.py
from datetime import datetime

def lambda_handler(event, context):
    global now 
    now = datetime.now()
    method_a()

def method_a():
    method_b()

def method_b():
    method_c()

def method_c():
# xはジョブの作成日時を表しています。
   time = now - x
   print(data)

これで無事、2回目以降も
ちゃんとnowが実行した日時を取得してくれるようになり
timeも上手く取得できました。

まとめ

Lambdaの関数インスタンスの再利用については
初耳だったので、とても勉強になりました。

あとは、グローバル変数はとても便利ですが
思わぬバグを引き起こす原因になりやすいということを
身を持って実感しました。

使い方には気を付けていこうと思います。

20
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?