自由気ままに書いちゃおう

好きなことをつらつらと・・・

AWS 初めてのLambda(本当の初心者向け2)

前回、用語の説明をメインにLambdaについて記載しております。

www.guri2o1667.work

 
今回は、実際にLambdaを使ってみたいと思います。
※実行環境はPython3.8です。

■Lambdaの初期設定の前に

ここではざっくりとどういったものを作成するのかを記載致します。
現時点では理解していなくても大丈夫です。

Lambdaでは、Lambdaで処理したい内容を「関数」として定義します。
関数を作成した際、デフォルトでは「lambda_function.py」というPythonファイルが自動的に生成されます。

f:id:guri2o1667:20200703105543p:plain

また、「lambda_function.py」で定義する関数名は、
「lambda_hundler(event,context)」というものを使用します。

f:id:guri2o1667:20200703105724p:plain

■流れ

1.関数の作成
2.テストの実行
3.ここまでのおさらい(概要)
4.ここまでのおさらい(詳細)
5.補足1:テストデータについて
6.補足2:contextについて
7.補足3:ハンドラーについて

■1.関数の作成

1.AWSコンソールからLambdaを起動します。

f:id:guri2o1667:20200703104232p:plain

2.左ペインから「関数」をクリックします。
※はじめて開いた方は、左ペインが折りたたまれているかもしれません。

3.「関数の作成」をクリックします。

f:id:guri2o1667:20200703104415p:plain


4.以下の通り選択し、「関数の作成」をクリックします。

関数名は「test1」、
ランタイムは「Python3.8」としています。
画面下部に記載されていますが、LambdaはCloudwatchLogsの利用が必須のため、ロールが新規作成されます。
f:id:guri2o1667:20200703104659p:plain

5.以下のような画面が表示されたことを確認します。

f:id:guri2o1667:20200703105513p:plain

■2.テストの実行

1.関数の画面の「テスト」をクリックします。

f:id:guri2o1667:20200703120025p:plain


2.「イベント名」に適当な名前を入力し「作成」をクリックします。

※ここでは、testeventとしました。

 

f:id:guri2o1667:20200703120852p:plain

3.再度「テスト」をクリックします。

f:id:guri2o1667:20200703132514p:plain


4.以下の通り、成功の旨が表示されていることを確認します。

f:id:guri2o1667:20200703132551p:plain


※「詳細」を展開すると、実行結果の詳細を表示できます。

f:id:guri2o1667:20200703132641p:plain

■3.ここまでのおさらい(概要)

まずはじめに関数(ここでは、test1)を新規作成しました。test1の配下に新規作成時にはデフォルトで「lambda_function.py」というPythonファイルが自動的に生成されました。

f:id:guri2o1667:20200703105543p:plain

また、「lambda_function.py」をみてみると下記の通り、自動的にコードが既に記述されていることが確認できました。

f:id:guri2o1667:20200703132936p:plain


テスト実施時に、テストデータを作成しました。
(作成はしましたが、設定は変更せず、そのまま利用しております。)

f:id:guri2o1667:20200703133019p:plain


で、テストを実行した結果、以下の通り結果が出力されました。

f:id:guri2o1667:20200703133112p:plain


これだけでLambdaのイメージがつかめた方が羨ましいです。
私はここまでやっても「だから何?てか、何しているかよくわからないし」って感じでした。笑

ということで、もう少し詳細を書きます。

■4.ここまでのおさらい(詳細)

関数のところから説明します。
Lambdaを始めるときに作成した関数ですが、関数と謳っておきながらフォルダです。
言ってしまえば、Lambdaで実装したいコードを纏めておくフォルダのことです。

f:id:guri2o1667:20200703133852p:plain


下記の画面は、「lambda_function.py」の中身を表示しているものです。
※タブのところにpy拡張子がない表示で記載されています。

f:id:guri2o1667:20200703132936p:plain


今度はこのコードの内容についてです。
Lambdaでは何かしらの処理をする際、イベントを受け取ります
そのイベントが lambda_handler(event, context)の中のeventに格納されます。
今回の場合ですとテストとして作成した以下画像の5行(実際には2行目から4行目のデータ)がeventに格納されます。

f:id:guri2o1667:20200703133019p:plain

※「上記テストデータが結果に表示されてないじゃん。」って思う方もいらっしゃるかと思います。こちらについても後ほど記述いたします。

こんな感じですね。

f:id:guri2o1667:20200703134629p:plain

続いて、Lambdaがeventとして受け取った情報を使うにしても使わないにしても
4行目から8行目までが実行されます。
今回は、returnの部分のデータ(6行目、7行目)が結果として表示されます。
実際に結果を見てみても、6行目、7行目と同じ内容が出力されています。

f:id:guri2o1667:20200703135104p:plain


先送りにしていたテストデータの内容が結果のどこにも出力されていない件ですが、
lambda_function.pyの中で、
受け取ったイベント(event)データを処理していないのでどこにも出力されておりません。

試しにlambda_function.pyを以下の通り、修正してみます。

f:id:guri2o1667:20200703141608p:plain

修正後のコードは以下のものです。

import json

def lambda_handler(event, context):
   return json.dumps(event, ensure_ascii=False)


この状態で「保存」(=「テスト」ボタンの横)をクリックし、
再度「テスト」を実行してみると
結果は下記の通り、テストデータで使用したものが出力されます。

f:id:guri2o1667:20200703141804p:plain


何が言いたいかというと、lambda_function.pyの中でeventを使うような処理を書かないと、出力結果には何も出てこないよってことです。

念のため、もう一つだけサンプルを。

import json
def lambda_handler(event, context):
    print(event['key1'])
    print(event["key2"])
    print(event["key3"])


こちらを実行した結果は以下の通りです。

f:id:guri2o1667:20200703164556p:plain


成功はしていますが今度は、今まで見てきた箇所に「null」と表示されております。
あれ?と思う方もいるかと思いますが、下の「ログ出力」欄を見ると、
value1 , value2 , value3 と表示されていることがわかります。

f:id:guri2o1667:20200703143409p:plain


ここで大事なことを一つ。
returnで指定した内容は結果の冒頭(=前述のものだとnullの箇所)に記載され、
print文なので記載した内容は「ログ出力」に記載されるということです。

■5.補足1:テストデータについて

今回、テストデータはJSON形式のもの(デフォルトのもの)を利用しました。
テストデータなので、他の内容でも処理可能です。
ただし、JSON形式のものがeventに格納されると最初のうちは思っていた方が良いです。

■6.補足2:contextについて

lambda_function.py内に記載されている lambda_handler(event, context):の記述ですが、eventには触れましたが、contextには触れていなかったのでここで触れておきます。

context(コンテキスト)には、ランタイム(プログラミング言語)ごとに事前に定義されている情報が格納されています。
例えば、以下のコードをlambda_function.pyに記述することで、リクエストID等が取得できます。

import json
import json
import time
def lambda_handler (event, context):
 print("Log stream name:", context.log_stream_name)
 print("Log group name:",  context.log_group_name)
 print("Request ID:",context.aws_request_id)
 print("Mem. limits(MB):", context.memory_limit_in_mb)
 # Code will execute quickly, so we add a 1 second intentional delay so you can see that in time remaining value.
 time.sleep(1) 
 print("Time remaining (MS):", context.get_remaining_time_in_millis())


参考ページ: 

Python の AWS Lambda context オブジェクト - AWS Lambda

 

■7.補足3:ハンドラーについて

私が一番理解するのに苦しんだのが、この「ハンドラー(Handler)」です。
Lambdaを勉強するにあたり、ハンドラーだけはどんな説明資料をよんでもしっくりきませんでした。
にもかかわらず、ハンドラーって用語たくさん出現するんですよ。。。
ということで、今の時点で私が理解している内容を記載致します。そのため、間違っていたらすみません。

ハンドラーとは、
Lambdaによる処理開始時に一番最初に実行される関数のことです。
つまり、event,contextを処理する関数は常にハンドラーということになります。
今回の例では、 lambda_handler(event, context): がハンドラーに該当します。
念のため記載しておくと、一番最初に実行される関数の"関数"という単語はdefで定義した、いわゆるPythonの関数に該当します。Lambdaを作成するときの関数ではありません。

ではLambda関数を作成した際にハンドラーを設定したかというと
自動的に設定されるため意識していなかっただけです。
「基本設定」欄にハンドラー情報が記載されています。

f:id:guri2o1667:20200703162355p:plain


こちらには初期値として「lambda_function.lambda_handler」と記載されております。
ドット区切りで記載されており、
ドットの前(lambda_function)は「Pythonファイル」です。

f:id:guri2o1667:20200703162529p:plain

ドットの後ろ(lambda_handler)は「Python関数名」です。
デフォルトでは、「def lambda_handler(event, context):」と書かれている部分です。

f:id:guri2o1667:20200703132936p:plain


ということは、「def lambda_handler(event, context):」を変更し、
「基本設定」もそれに合わせて更新してあげれば、
lambda_hundler以外の名前(関数名)をハンドラーとして定義できることになります。

やってみます。

まず、関数名を以下の通り変更しました。
変更前: lambda_handler(event, context):
変更後: python_function_handler(event, context):

f:id:guri2o1667:20200703163054p:plain

続いて、「基本設定」を変更します。
「編集」をクリックし、ハンドラ項目を修正し「保存」をクリックします。

f:id:guri2o1667:20200703163129p:plain

 

f:id:guri2o1667:20200703163325p:plain


設定変更後は下記の通りです。無事にハンドラの設定が変更されています。

f:id:guri2o1667:20200703163420p:plain


テストを実施します。
問題なく実施できているかと思います。

f:id:guri2o1667:20200703164157p:plain

では、Python関数側の名前をわざと変更します。
実施意図は、ハンドラ情報とPython側の関数名が一致しないときの動作を確認するためです。
現在: python_function_handler(event, context):
基本情報の設定: python_function_handler(event, context):
変更後: lambda_handler(event, context):  ※元に戻しました

この状態でテストを実行すると、下記の通りハンドラが見つからないため、
エラー表示となります。

f:id:guri2o1667:20200703163810p:plain

以上です。
次回はトリガーを利用したLambdaの動作確認を行いたいと思います。

 

 

www.guri2o1667.work

 

www.guri2o1667.work