Snap Startを有効化したAWS Lambda関数をTerraformで作る

# 環境
- Terraform v1.5.4
- AWS Provider v5.10.0
- macOS Ventura 13.5
- JDK 17

# 関数のコード
```java
package com.example;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;

public class HogeFunction implements RequestHandler<String, String> {
    public HogeFunction() {
        // aws lambda invokeで実行する際コンストラクタは実行されないことを確認するために、２秒スリープする
        try {
            Thread.sleep(2000);
        } catch (Exception ignore) {}
    }

    @Override
    public String handleRequest(String input, Context context) {
        System.out.println("Executing function...");
        return "SUCCESS";
    }
}
```


# Terraformコード
```tf:snap_start.tf
# Lambda関数に適用するIAMロール
resource "aws_iam_role" "hoge_lambda_role" {
  name               = "hoge-lambda-role"
  assume_role_policy = jsonencode({
    Version   = "2012-10-17"
    Statement = [
      {
        Action    = "sts:AssumeRole"
        Effect    = "Allow"
        Sid       = ""
        Principal = {
          Service = "lambda.amazonaws.com"
        }
      },
    ]
  })
}

# Lambda関数がCloudWatch Logsにログを出力できる権限を付与する
resource "aws_iam_role_policy_attachment" "hoge_lambda_role_policy_attachment" {
  role       = aws_iam_role.hoge_lambda_role.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}

locals {
  lambda_zip_path = "hoge.jar"  # Lambda関数のJARファイルのパス
}

# Lambda関数の作成
resource "aws_lambda_function" "hoge_lambda" {
  function_name = "hoge-lambda"  # 任意のLambda関数名
  role          = aws_iam_role.hoge_lambda_role.arn  # Lambda関数に適用するIAMロール
  handler       = "com.example.HogeFunction"  # RequestHandler実装クラスのFQCN
  architectures = ["x86_64"]  # Snap Startはx86_64のみ対応
  runtime       = "java17"  # Snap StartはJava 11・17のみ対応
  memory_size   = 256  # 任意のメモリサイズ(MB単位)
  package_type  = "Zip"
  filename      = local.lambda_zip_path  # Lambda関数のJARファイルのパス
  source_code_hash = filebase64sha256(local.lambda_zip_path)  # JARファイルに変更があればapplyするようにする
  timeout = 3
  publish = true  # これをtrueにするとSnap Startが有効化される

  snap_start {
    # これを記述するとSnap Startが有効化される
    apply_on = "PublishedVersions"
  }
}

# Lambda関数のエイリアスを作成する
# これを作っておくと、最新バージョンの関数をいつも `関数名:latest` で呼び出せるようになる
resource "aws_lambda_alias" "hoge_lambda_alias" {
  function_name    = aws_lambda_function.hoge_lambda.function_name
  function_version = aws_lambda_function.hoge_lambda.version
  name             = "latest"
}
```

ほとんどは普通にLambdaを作るときと同じです。Snap Startに関するポイントは下記の２点だけです。

```tf
  publish = true  # これをtrueにするとSnap Startが有効化される

  snap_start {
    # これを記述するとSnap Startが有効化される
    apply_on = "PublishedVersions"
  }
```

`terraform apply`でLambda関数を作成してください。

# Snap Startが有効になっているか確認
`aws lambda get-function-configuration --function-name hoge-lambda:latest`を実行して、次のようになっていればOKです。

```json
    "State": "Active",
    ...
    "SnapStart": {
        "ApplyOn": "PublishedVersions",
        "OptimizationStatus": "On"
    },
    ...
```

# 関数の実行
```shell:関数を実行するコマンド
aws lambda invoke --function-name hoge-lambda:latest \
response.txt
```

> CLIを実行するIAMユーザーに、AWS Lambdaの実行権限(`lambda:InvokeFunction`)が必要です。

# ログの確認
```shell:ログを確認するコマンド
aws logs tail /aws/lambda/hoge-lambda --follow
```

```shell:１回目の実行ログ
RESTORE_START Runtime Version: java:17.v9       Runtime Version ARN: arn:aws:lambda:ap-northeast-1::runtime:dbba1971e930ffa96516a5f974314066b67b3aadbd7a890b193c3d9a2385cf54
RESTORE_REPORT Restore Duration: 422.93 ms
START RequestId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Version: 1
Executing function...
END RequestId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
REPORT RequestId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx  Duration: 232.90 ms     Billed Duration: 304 ms Memory Size: 256 MB        Max Memory Used: 77 MB  Restore Duration: 422.93 ms     Billed Restore Duration: 71 ms
```

リストアに少し時間がかかっていることが分かります。しかし、総実行時間は１秒に満たないため、コンストラクタ（中に`Thread.sleep(2000)`は書いてある）は実行されていないことが分かります。

もう１回実行すると、リストアが行われずにすぐ本来の処理が実行されていることが分かります。

```shell:2回目の実行ログ
START RequestId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Version: 1
Executing function...
END RequestId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
REPORT RequestId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx  Duration: 1.57 ms       Billed Duration: 2 ms   Memory Size: 256 MB        Max Memory Used: 77 MB
```

# 参考資料
- [AWS公式ドキュメント](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/snapstart.html)
- [Terraform AWS Provider公式ドキュメント](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function)