GitHub Actions + SQS + Lambda で main ブランチへ merge してから15分後に cloudfront キャッシュを削除する

# 処理の概要
1. GiHub Actions から、AWS SQS にメッセージを送信
2. SQS がメッセージ受け取ったら、15分後に Lambda を呼び出す
3. Lambda が aws create-invalidation コマンドを利用し、CloudFront キャッシュ削除を行う

# 何故そんな回りくどい事をするのか？

普通に GitHub Actions から create-invalidation を利用していましたが、AWS ECS を利用しているため古いタスクが終了し新しいタスクに切り替わる前に再度ユーザーがアクセスし、古いタスクのキャッシュが生成されるという状態になっていました

main ブランチへの merge から10分程度で ECS のタスクが切り替わっているので、余裕を持って15分後くらいにはキャッシュを削除させたかった

# 全体図

![AWS.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76272/5a8525d9-6137-d502-c740-f8c4a0e1e47b.png)

# 手順

## Lambda の作成

2個所のみ設定で問題ありません。詳細設定などは必要があれば設定してください。

関数名 : （※任意。create-invalidation とかでもOK)
ランタイム : Node.js 20.x

![CreateLambda.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76272/1f6749c1-c255-b896-f5fd-83046f49e100.png)

※雀の涙かもしれないですが、コストを少しでも減らしたいのでしたらアーキテクチャに「arm64」を選択

## 作成した Lambda 関数に権限を追加する

作成した関数に移動し、「設定 → アクセス権限 → ロール名」を順にクリック

![スクリーンショット 2024-04-10 125218.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76272/a10706f6-8859-5c13-e887-23ff05f71716.png)

「権限の追加」を選択

![スクリーンショット 2024-04-10 125508.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76272/1dc5450b-4c1f-bcad-2c4c-a8092add5c25.png)

### Cloud Front のキャッシュを削除するための権限


「CloudFrontFullAccess」を付与

※必要なのは「cloudfront:CreateInvalidation」だけなので、カスタム権限を作成してもいいです

### SQS と連携するための権限

「AWSLambdaSQSQueueExecutionRole」を付与

## Lambda コード

Lambda 関数に戻り、「コード」を選択

![スクリーンショット 2024-04-10 130024.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76272/29e6b461-8831-d268-f101-4aa386b473d2.png)


大きな赤枠に下記のコードをペーストしてください

```javascript
import { CloudFrontClient, CreateInvalidationCommand } from "@aws-sdk/client-cloudfront";
const cloudfront = new CloudFrontClient({ region: "us-east-1" });

export async function handler(event) {
  // xxxxxxxxxxxxxx にはキャッシュを削除したい cloudfront のディストリビューションidを入力
  const distributionIds = [
    'xxxxxxxxxxxxxx', 
  ];
  
  for (const distributionId of distributionIds) {
    
    const command = new CreateInvalidationCommand({
      DistributionId: distributionId,
      InvalidationBatch: {
        CallerReference: `jcation-invalidation-${Date.now()}`,
        Paths: {
          Quantity: 1,
          Items:  [
            "/rentacar/*"
          ],
        },
      },
    });

    try {
      const response = await cloudfront.send(command);
      console.log(response);
    } catch (error) {
      throw new Error(error);
    }
  }
}
```

### CloudFront のディストリビューションid とは

CloudFront 画面のこちら

![スクリーンショット 2024-04-10 130336.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76272/46b080e2-a27f-a88c-cbd3-f1336b5c83fe.png)

## メッセージを受信するSQSを作成

SQS → キューを作成 をクリック

名前：（※任意）
受信遅延：15分に設定

それ以外の設定はお好み。

![スクリーンショット 2024-04-10 130636.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76272/7108c8ce-6669-bdc1-aef6-4b0fc4f43d41.png)

## Lambda 関数に SQS をトリガーとして登録

「トリガーを追加」を選択

![スクリーンショット 2024-04-10 131038.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76272/0193c053-e50b-0ad9-dbae-1ef91e64a5e2.png)

SQSを選択
SQS queue : 先程作成した SQS を選択
Activate trigger にチェック

![スクリーンショット 2024-04-10 131223.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76272/78e8b3fe-3079-844a-d014-d5fcc2fa6b38.png)

で準備完了

## GitHub Actions 

下記の yml を workflows に追加

※ --message-body に "trigger" としていますが、何でもOK。好きな言葉を入れてください

```yml
name: CloudFront Clear Cache

on:
  workflow_dispatch:
  push:
    branches:
      - main

jobs:
  cloudront-clear-cache:
    runs-on: ubuntu-latest

    steps:
    - name: Send message to SQS queue
      run: |
        aws sqs send-message --queue-url https://sqs.ap-northeast-1.amazonaws.com/{AWS Account ID}/{SQSキューの名前} --message-body "trigger"

```

## main に push なり merge なりして動作確認

お疲れ様でした

# まとめ

インフラの理解がイマイチなのでこの方法になりましたが、もっといい方法あるかも。いやきっとある。