AWS Lambdaを使って関数を定期実行する

# 経緯

Pythonで動くコードを定期実行させたくなった。
タスクスケジューラ―でやるにしても電源オフ時に起動できるようにBIOSの設定をするのが面倒。
また、どこかでサーバを立てて実行させるほどの気力はない。
ので、AWS Lambdaを使って関数を定期実行させることにした。

# 目的

関数の定期実行ができるまでをメモ程度に記録する。
AWS Lambdaに関するナレッジはネットに溢れているが、自分にとって意外なハマりどころや勘所があったので後から見返せるようにまとめたい。

# AWS Lambdaとは
[AWS Lambda とは - AWS Lambda (amazon.com)](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/welcome.html)

# AWS上の環境

- リージョン：東京
- ランタイム：Python 3.9（関数の作成時に設定）

# 実行コードの概要

ファイルは単体で拡張子は「.py」。
実行するコード中には以下の通り、import文があるので外部ライブラリをコードが読み込めるようにしなければならない。手順は後述する。

```python
import requests
import pandas as pd
```

# 関数の作成～実行準備完了までの手順
## 関数を作成する

以下リンク先の「****関数を作成する****」を参照しながら関数を作成する。
3.bではNode.jsを指定しているが、今回はRuntimeにPython 3.9を指定する。

▼関数の作成方法
[Lambda の開始方法 - AWS Lambda (amazon.com)](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/getting-started.html)

## コードをデプロイする

Lambda＞関数＞{関数名}の順に進むと、画面上部には「関数の概要」が、下部にはタブがあり「コード」を選択するとコードソースが表示される。
デフォルトだと{関数名}＞lambda_function.pyの階層でファイルが配置されている。
今回は特に拘りはないので、このファイルに実行コードを貼り付けた。

また、デフォルトだと`lambda_function.py`の`lambda_handler`メソッドを見て実行するようになっているため、
このようにコード中でメソッドを定義しておく。

```python
def lambda_handler(event, context):
  # 実行コードの中身
```

コードを貼り付けたら、Deployボタンを押して反映させる。

![デプロイ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299342/622c8a5c-9fec-9a53-3dd9-1e0955124aaa.png)


【ちなみに】
関数のデプロイは上記以外にもzip形式のフォルダやコンテナイメージとしても可能。

▼zip形式もしくはコンテナイメージとしてのデプロイ方法
[Lambda 関数のデプロイ - AWS Lambda (amazon.com)](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-deploy-functions.html)

## Amazon EventBridgeを使ってトリガーを設定する

「トリガー」で関数の実行タイミングを登録する。
今回は毎日日本時間の午前3時15分に実行させたかったのでcron式で「**cron(15 18 * * ? *)**」と指定した。
説明は以下リンクと下の【ハマりどころ】の通り。

▼トリガーの追加方法
[Amazon EventBridge (CloudWatch Events) でAWS Lambdaを使用する - AWS Lambda](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/services-cloudwatchevents.html)

▼cron式/rate式の指定方法
[スケジュールに従って実行する Amazon EventBridge ルールの作成 - Amazon EventBridge](https://docs.aws.amazon.com/ja_jp/eventbridge/latest/userguide/eb-create-rule-schedule.html)

【ハマりどころ】
> スケジュールされたイベントはすべて UTCのタイムゾーンを使用し

上記ドキュメントの記述通り、入力された時間はUTCとして登録される。
なので、午前3時15分に実行させたければUTCにおける午後6時15分として登録する。
マネジメントコンソール上から定期実行のスケジュールをトリガーとして設定する場合、以下の2つのやり方で設定できる。

1. Lambda＞関数＞{関数名}の順に進み、EventBridgeのアイコン直下にある「＋トリガーを追加する」ボタンを押し、入力を進める
2. Amazon EventBridge＞ルール＞ルールを作成の順に進み、入力を進める

どちらでもよいが、「2.」の方が入力したcron式に対してローカルタイムゾーンの場合は何時になるのか確認できるのでやりやすいと感じた。

## Pythonの外部ライブラリを読み込ませる

関数内で使用する外部ライブラリを「レイヤ」で指定する。
コードをデプロイする段階で実行コードと一緒くたにしてアップロードしても動作するが、
ライブラリを自分で用意しようとすると、
1. ライブラリのインストール
2. zip化したフォルダのアップロード

が必要で、特定のフォルダにインストールさせたり、パッケージ構成を考慮して「python」フォルダにまとめたりと面倒。
拘りがなければ既存で利用可能なものをまずは見繕ったほうがよいと感じた。
ので、今回は既存で存在するARNを指定した。

▼ARNとは
[Amazon リソースネーム (ARN) - AWS 全般のリファレンス](https://docs.aws.amazon.com/ja_jp/general/latest/gr/aws-arns-and-namespaces.html)

色々調べてみると以下リポジトリに行き着いた。
[https://github.com/keithrozario/Klayers](https://github.com/keithrozario/Klayers)
[deployments](https://github.com/keithrozario/Klayers/tree/master/deployments)の下にあるフォルダを見て対象のランタイムとリージョンを選択していくと存在するライブラリのARNが見られる。

▼レイヤにおける指定方法
[Lambda 関数でのレイヤーの使用 - AWS Lambda (amazon.com)](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/invocation-layers.html)

## テスト実行する
あとはスケジュール実行されるのを待つのみ、と早合点すると次回実行まで設定の漏れに気がつかない。
ので、テスト実行をして動作確認をおこなう。

▼テストイベントの設定方法
※「新しいイベントを作成」を選択して各種入力項目を埋めていく
[コンソールでの Lambda 関数のテスト - AWS Lambda (amazon.com)](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/testing-functions.html)

## タイムアウトを設定する

テスト実行してみるとコンソールに以下エラーログが出力された。

タイムアウトが発生している模様。
タイムアウトはデフォルトで3秒で設定されているので、それを変更してあげれば解決する。
画面下部の「設定」タブから一般設定の「編集」を押し、タイムアウトの秒数を編集すればよい。

```json
{
  "errorMessage": "2022-09-27T10:49:45.595Z XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX Task timed out after 3.02 seconds"
}
```

## システム日時を設定する

気を取りなおして実行してみると今度はシステム日時の実態が想定と異なっていた。

夜中の3時34分の実行だったが、コード中でシステム日時を出力させるようにして見ると以下日時になっていた。
9時間の時間差なのでUTCが出力されている模様。

```json
2022-09-28 18:34:37.249843
```

日本時間のシステム日時が取得されてほしいので、環境変数で設定する。
環境変数の設定方法は以下の通り。
[AWS Lambda 環境変数の使用 - AWS Lambda (amazon.com)](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/configuration-envvars.html)

キーを「`TZ`」、値を「`Asia/Tokyo`」とした。
再度コードを実行させてみると以下の通り日本時間で出力された。

```json
2022-09-29 03:51:15.112983
```

# ****CloudWatch Logsを使って****実行状況を確認する

想定しているタイミングで実行されているか知るためにログを確認する。
Lambda＞関数＞{関数名}の順に進み、画面下部のタブ群の中にある「モニタリング」＞「ログ」の中で実行ログが一覧化されている。
表示時間はUTCとなっている。ローカルタイムゾーンの時間を表示させたい場合は「カスタム」＞「Local Time Zone」を選択する。

# 感想
基本操作についてはAWSのドキュメントに記載があったのでおおよその設定はできた。
が、所々にハマりどころがあり、地味に苦労した。
AWS Lambdaを設定する上での基本知識は身についたので、今後AWS Lambdaを使う機会が来たらやりたいことに合わせて上乗せで調査＆設定をしていく。