初心者のAWS lambda学びまとめ

## 概要
仕事でAWS lambdaを使う機会があったので、学んだことや注意事項のまとめです。
初心者で同じような境遇の人の参考になれば嬉しいです。

## 使ったサービス
- lambda
- API Gateway
- cdk (lambda, API Gatewayのコードを管理）

## lambda自体の設定
### ライブラリを使う
lambdaのコード内で、Python標準ではないライブラリを使いたい場合は、ライブラリのコードもどこかに保持しておく必要があります。以下2つの選択肢があるようです。（他にもあるのかもしれません。）

- lambdaレイヤーに入れる
ライブラリをzipにしてlambdaレイヤーというところにアップロードする方法です。

わかりやすかった記事：

https://qiita.com/__DASHi__/items/268062f0dba0e93170f2

[注意]
zipにするフォルダ名は注意が必要です。（pyhonのライブラリなら、`python` にする）
- その時にはまって書いた記事：

https://qiita.com/sioiriomame/items/8da88954b685d0ac3784

ちなみに、lambdaレイヤーにはライブラリ以外のものもアップロードできて、以下のように開けるようです。（lambdaレイヤーは、`/opt` 以下に展開されるため。）また、複数の関数間で共有することができるそうです。

```python
with open("/opt/zipにしたフォルダ名/file名", "r") as f:
```

- Bundlingオプションを使う
自分では使っていないが、他の人がこちらを使っていました。インストールするライブラリとコマンドを書いておくことで、アップロードしてくれるようです。デプロイ後は、lambdaレイヤーではなく、lambda本体の中のディレクトリに含まれているようです。

https://kakakakakku.hatenablog.com/entry/2024/03/27/201653

### コールドスタートを防ぐ (プロビジョニングされた同時実行数)
コールドスタートでレスポンスが遅くなるのを防ぐために、事前に初期化しておく実行環境の数を指定できます。（ただ、その分のコストはかかるそうです。）

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/provisioned-concurrency.html

同時実行数（ピーク時の秒間）の1/3位を設定しておくと良いと教えてもらいました。

cdkでは、エイリアスに対して以下のように設定できます。

```ts
const alias = new lambda.Alias(this, 'SampleAlias', {
      aliasName: "sampleAlias",
      version: sampleLambda.currentVersion,
      provisionedConcurrentExecutions: 5,
    });
```
[注意]
エイリアス名と関数名を同じにした状態でデプロイしたところ、以下のエラーが発生しました。違う名前の方が良いみたいです。

```
Resource handler returned message: "Provisioned Concurrency configuration failed to be applied. Reason: FAILED" (RequestToken: xxx, Handler
ErrorCode: NotStabilized)
```

https://github.com/aws/aws-cdk/issues/6016

### デプロイ時のダウンタイムを最小化 (エイリアス)
API Gatewayからは、lambdaのエイリアスを呼び出すようにしておくことで、エイリアスに紐づくバージョンを変更するだけで、バージョン変更ができます。デプロイ時のダウンタイムを最小化に役立ちます。

https://zenn.dev/tech4anyone/articles/2760805b2fa64d

https://qiita.com/fkooo/items/1b24e01252e145a378db

[注意]
API Gatewayからlambdaのエイリアスを呼び出すと、管理コンソールからコード編集しても、エイリアスに紐づくバージョンを変えなければ変更が反映されません。よく考えればわかることなのですが、気がつくまでにしばし時間を要しました。

### 起動失敗について
lambdaは、稀に起動に失敗することがあるそうなので、呼び出し側でリトライ処理を入れた方がいいとのこと。

https://qiita.com/gotousua/items/b089874192e50f7cace5

## API Gateway関連
### lambdaのエラーを出し分ける
「プロキシ統合」と、そうでない場合でやり方が変わります。プロキシ統合は、簡単に言うと、API Gatewayからlambdaにそのまま値を渡し、lambdaから返ってきた値をそのままAPI Gatewayのレスポンスとして返す形式です。
今回は「プロキシ統合」だったので、lambda側で例外をキャッチした部分でステータスコードとエラーメッセージを指定して返すようにしました。

```python
except ConnectionTimeout as e:
        logger.error(e)
        return {
            'statusCode': 504,
            'body': json.dumps({'message': 'タイムアウトが発生しました'})
        }
```

わかりやすかった記事：

https://qiita.com/yuuwatanabe/items/a3bd65e709f20574b6db

https://qiita.com/syakoo/items/f58c15b9795d7772effa

### 独自のドメインを設定する (カスタムドメイン設定)
API Gatewayのドメインを、指定したドメインに設定することができます。この手順を参考に実施しました。

https://nekoniki.com/20220517_aws-cdk-apigateway-custom-domain

（カスタムドメイン自体の設定はインフラチームに実施いただいていたのを、cdk化しただけなので、元の設定は完全に理解できているわけではないですが。）


## cdk関連
cdkのベースは別の方に作ってもらったため、自分でゼロから作るのはできていないので、今度ゼロから作ってみたいです。

### 環境ごとに名前をつける
環境ごとに名前をつけないと、同じAWS環境上に複数環境用のstackが存在する場合に、上書きされてしまうという事象が発生しました。

https://dev.classmethod.jp/articles/aws-cdk-deploy-dev-and-prod-stack/

### stackの定義を増やす
一つのプロジェクトに複数stackを入れることもでき、`/lib` 配下に、stackごとのファイルを作り、`/bin` 配下のファイルにstackを追記します。stackを分けるかどうかについては、削除やデプロイを分けたいかがポイントになりそうという話がありました。

https://nekoniki.com/20220208_aws-cdk-multi-stack

### stackを削除する
`cdk deploy` した時に、裏では Cloud Formationのスタックがデプロイされています。
stackの削除は、コマンドで `cdk deploy stack名` でできますが、なかなか削除されない時は、CloudFormation > スタック名 > リソース から、リソースごとの削除状況を確認することができます。画面から削除することもできます。

### 削除保護の設定
CloudFormation の画面から、stackの削除保護 (一度無効にしなければ削除できなくなるため、誤って削除するのを防ぐことができる）を設定できます。が、cdkでデプロイすると設定が上書きされて無効になってしまうため、削除保護を設定したい場合は、cdk側で設定が必要なようです。

https://dev.classmethod.jp/articles/configure-deletion-protection-for-cloudformation-stack-with-aws-cdk/

`/bin` 配下のstack定義で、各stackを定義する時に１行追加するだけです。

```diff_typescript
new SampleStack(app, `SampleStack-${targetEnv}`, {
+  terminationProtection: true,
   env: { 省略 },
}
```

## その他
### CloudWatchの「すべてのログストリームを検索」
lambdaのログは、CloudWatch で確認することができます。（lambdaの画面から、モニタリング > CloudWatchログを表示 から表示できます。）
これは、lambdaのログに限らないのかもしれないのですが、CloudWatchの「ログストリーム」の「最終のイベント時刻」が、画面を読み込み直しても更新されないことがありました。（「ログが出力されない！と騒いだが実際は出力されていた。）「すべてのログストリームを検索」で検索するのが便利なようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661656/173dcd85-95e5-d57f-549e-a695c5152531.png)



## おわりに
完全に理解した！とは言えないけれど、学びは多かったので次に生かしたいです。初めてだったので、社内の経験のある方が、色々説明と資料を送ってくださって本当にありがたかったです。感謝...。