DynamoDBさわってみた（DynamoDB Stream, TTL）

# DynamoDB Streamの有効化
## 設定状況の確認
設定状況はマネコンの 一般的な情報 > 追加情報から確認できます。

![cap01.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/5c8b9def-5eec-5fca-74fe-998e3c165a45.png)

## 有効化
「エクスポートおよびストリーム」タブから設定します。

![cap02.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/0a8bb80f-c2ea-ddf2-89ff-aa5c3d52c63a.png)

streamにpushする情報を選択できます。
トリガーされるlambdaがeventとして処理できる情報になります。
今回は「新旧イメージ」を選択します。

![cap03.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/3214896b-4e65-f6ad-9429-9cdddadcf2c8.png)

ストリームが有効化されます。
また、ストリームそのもののARNも定義されます。
トリガーに設定するlambdaのサービスロールには、dynamodb本体ではなく、このstreamへのアクセスポリシーが必要です。

![cap04.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/0e0dfa48-23cc-28c2-3b7c-b5bee767fdcb.png)

## トリガーの追加
### lambdaサービスロールの準備
トリガーで実行されるlambdaのサービスロールを設定します。

https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/iam-policy-read-stream-only.html

上記ガイドを参考にします。

```policy.json
{
    "Statement": [
        {
            "Action": [
                "logs:PutLogEvents",
                "logs:CreateLogStream"
            ],
            "Effect": "Allow",
            "Resource": "arn:aws:logs:ap-northeast-1:123456789012:log-group:/aws/lambda/lambda:*"
        },
        {
            "Action": [
                "dynamodb:ListStreams",
                "dynamodb:GetShardIterator",
                "dynamodb:GetRecords",
                "dynamodb:DescribeStream"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:dynamodb:ap-northeast-1:123456789012:table/example/stream/2024-09-07T11:19:49.079/*"
            ]
        }
    ],
    "Version": "2012-10-17"
}
```

#### ```Cannot access stream``` と注意されてしまう場合
<font color="Red">**※バグなのか、2024/09/07時点ではドキュメントを参考にした上記ポリシーではトリガー作成時に以下エラーがでてしまいます**</font>

![cap09.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/9b2888d4-ea6b-3962-190e-3c2d51db691a.png)

原因ですが、IAMポリシーのリソースブロックに ```${Stream_Arn}``` が存在しない場合、上記エラーがでてしまいます。

ドキュメントにある通り、許可を与える対象は ```${Stream_Arn}``` ではなく、 ```${Stream_ARN}/*``` なのですが、エラー扱いにされてしまいます。

```policy.json
            "Resource": [
                "arn:aws:dynamodb:ap-northeast-1:123456789012:table/example/stream/2024-09-07T11:19:49.079",
                "arn:aws:dynamodb:ap-northeast-1:123456789012:table/example/stream/2024-09-07T11:19:49.079/*"
            ]
```

今回は、上のようにポリシーを設定し、トリガー作成完了後、不要な ```${Stream_Arn}``` のほうを削除しました。

### lambdaの作成
#### トリガーで実行されるlambda
受け取ったevent情報内のレコードをそのままログ出力するlambdaを作成しました。
```index.js
exports.handler = async (event, context) => {
    console.log("========================================");
    console.log(event);
    event.Records.forEach((record, index) => {
        console.log(index);
        console.log('%o', record);
    });
    console.log("========================================");

    return {
        "statusCode": "200",
        "body": JSON.stringify({ "test": "value" })
    };
};
```

#### DynamoDBに書き込むlambda
5件のレコードをINSERTするlambdaを作成しました。

```index.mjs
import { BatchWriteItemCommand, DynamoDBClient } from "@aws-sdk/client-dynamodb";

const client = new DynamoDBClient({});

export const handler = async (event, context) => {
    const command = new BatchWriteItemCommand({
        RequestItems: {
            example: [
                {
                    PutRequest: {
                        Item: {
                            id: { N: "1" },
                            name: { S: "White Chocolate Chip" },
                        },
                    },
                },
                {
                    PutRequest: {
                        Item: {
                            id: { N: "2" },
                            name: { S: "White Chocolate Chip" },
                        },
                    },
                },
                {
                    PutRequest: {
                        Item: {
                            id: { N: "3" },
                            name: { S: "White Chocolate Chip" },
                        },
                    },
                },
                { PutRequest: {
                        Item: {
                            id: { N: "4" },
                            name: { S: "White Chocolate Chip" },
                        },
                    },
                },
                {
                    PutRequest: {
                        Item: {
                            id: { N: "5" },
                            name: { S: "White Chocolate Chip" },
                        },
                    },
                },
            ],
        },
    });

    const response = await client.send(command);
    console.log(response);
    return response;
};
```

https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/javascriptv3/example_code/dynamodb/actions/batch-write-item.js




### トリガーの設定

DynamoDBのマネコンまたはlambdaのマネコンから設定できます。

![cap05.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/4edd5500-2377-b37a-f6a2-40f17f159552.png)

DynamoDBからは「トリガー」という機能で表現されています。
lambda側からは「イベントソースマッピング」という機能として表現されます。SNSとかと同じです。

今回はlambdaから設定してみます。

![cap06.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/c71805ff-61d0-87a9-f02c-355247a30ed8.png)

トリガー追加を選択します。

![cap07.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/1e089f06-70ca-b7aa-367f-265276806b6e.png)

トリガーの設定を埋めていきます。
動作確認のために、バッチサイズを2にしておきます。
追加ボタンをクリックします。

![cap10.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/bc5a278f-055a-6c11-ca53-b9f870f99aec.png)

イベントソースマッピングが設定されました。

## 動作確認
レコードをINSERTするlambdaを実行します。
DynamoDBに5件レコードが追加され、トリガーに設定されたlambdaが5件分のレコードをログ出力してくれるはずです。

cloudwatchを確認します。
ログストリームが2つできてます。

![cap12.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/c609aa23-3374-280e-79a6-51bddd9555a0.png)

片方のログを確認してみます。
トリガーされた関数が、1度の実行で、2件分のレコードを受け取っているのが確認できます。
バッチサイズ設定が有効に働いていることが確認できました。

![cap14.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/3bff5853-8e52-c9b9-513f-542d7c58bfae.png)

他方のログを確認してみます。
残る3つのレコードが2回に分けてログ出力されています。

![cap13.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/a721b2f5-5b2a-ed81-c23a-27d817b076c0.png)

バッチサイズを上回るレコードのCRUDが発生したときのトリガーの挙動が確認できました。
バッチサイズ上限を守りながら、全てのレコードを並列でトリガー先へ通知するようです（lambdaのログストリームが2つできたことから、並列実行されたことが類推できます）。

良い感じの機能ですね！！

# TTL
TTL機能も試してみます。
セッションなどの一時データを保存する場合、あると便利な機能ですね。

## 設定状況の確認
設定状況はマネコンの 一般的な情報 > 追加情報から確認できます。

![cap15.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/2230733b-09e1-423d-acd3-9d964bd6c189.png)

## レコードの準備
動作確認のため、ttl属性に適当なUNIX時間形式のNumberを設定したレコードを2件追加します。
一件目は1時間前を指しています。2件目は遠い未来ですね。

![cap18.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/2928d440-f2bc-08ca-0b92-c325d2b7abe2.png)

https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/TTL.html

## 有効化

「追加の設定」タブから設定します。

![cap16.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/004cc298-def5-67b9-d836-d1f82fec4b33.png)

中段にありました。

![cap17.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/0d8504f5-8f18-6402-4926-6c5d937826bc.png)

「オンにする」をクリックすると、設定画面が表示されます。
TTL属性名を入力し、プレビューを実施します。

![cap19_0.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/01ae70ef-bcc0-b314-2b64-d444bc5d6767.png)

1件削除候補が表示されました。2件目のレコードは遥か未来なので、動作は大丈夫そうです。

![cap19_1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/9e985d94-065d-cbda-4f64-a89b46db04f3.png)

「TTLをオンにする」をクリックします。

設定が有効化されていることを確認しました。

![cap21.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/98e03576-1ccf-a41a-e26f-da7aaf4fcc9c.png)

少し待つと、先ほどTTL機能の削除候補になっていたレコードが削除され、グラフに表示されていました。

![cap22.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/2bf18709-2ad7-89c8-b53b-3afab898d3af.png)

やったー！

# おわりに
DynamoDBの主力機能のうち2つを実際にさわってみました。
たのしかったです。