AWS Lambda と Fastly instant purge を利用して S3 コンテンツの更新を即時反映する

Fastly CDN の特徴のひとつに、Instant purge（コンテンツの即時削除）があります。通常、CDN では更新の多いコンテンツはキャッシュすることができませんが、Fastly では Purge を即座に行うことが可能であるため、更新の多いコンテンツでもキャッシュすることが可能です。
ただし、コンテンツが変更されるたびに Instant purge を手動で行うのは理想的な運用とはいえません。ここでは AWS Lambda を利用して、S3 でのファイル更新を検知して、自動的に Instant purge を実行する方法を紹介します。

# Lambda の設定
1. Services から Lambda を選択し、Create a Lambda function をクリックします
2. blueprint が表示されますが、ここでは `Blank Function` を選択します
3. トリガーの設定画面が表示されるので、`S3` を選択し、Bucket にコンテンツが配置される S3 バケットを選択し、Event type を PUT とします
![Screen Shot 0029-07-18 at 21.06.54.png](https://qiita-image-store.s3.amazonaws.com/0/149542/1dd1dac5-e85b-cdfe-1353-062fb60914f6.png)
4. Name / Description を入力し、Runtime はデフォルトの `Node.js` を選択します。
![Screen Shot 0029-07-18 at 21.11.26.png](https://qiita-image-store.s3.amazonaws.com/0/149542/d56e7a14-71f6-07cb-1ce0-56c710c8da02.png)
5. Code は下記のように設定します。hostname を Instant purge を行うドメインに変更してください。
下記のコードでは、アップデートされたパスを `key` に格納し、options にドメイン、ポート番号、method(purge のため、PURGE) と共に設定し、`http.request` で Instant purge のリクエストを送信しています。

```
console.log('Loading event');
var aws = require('aws-sdk');
var s3 = new aws.S3({apiVersion: '2006-03-01'});
var http = require('http');

exports.handler = function(event, context) {
   console.log('Received event:');
   console.log(JSON.stringify(event, null, '  '));
   // Get the object from the event and show its content type
   const bucket = event.Records[0].s3.bucket.name;
   const key = event.Records[0].s3.object.key;
   s3.getObject({Bucket:bucket, Key:key},
      function(err,data) {
        if (err) {
           console.log('error getting object ' + key + ' from bucket ' + bucket + 
               '. Make sure they exist and your bucket is in the same region as this function.');
           context.done('error','error getting file'+err);
        }
        else {
           console.log('CONTENT TYPE:' + data.ContentType + ' bucket: ' + bucket + ' path: ' + key);
           context.done(null,'');
        }
      }
   );

  var options = {
    hostname: 'www.example.com',
    port: 80,
    path: '/' + key,
    method: 'PURGE',
  };
  
  callback = function(response) {
  var str = '';

    //another chunk of data has been recieved, so append it to `str`
    response.on('data', function (chunk) {
      str += chunk;
    });

    //the whole response has been recieved, so we just print it out here
    response.on('end', function () {
      console.log(options.hostname + ':' + options.port + options.path + ' method:' + options.method);
      console.log(str);
    });
  }

  http.request(options, callback).end();
};
```

6 . Role は `Choose an existing role` を選択し、Existing role を選択します。
![Screen Shot 0029-07-18 at 21.14.43.png](https://qiita-image-store.s3.amazonaws.com/0/149542/014f1fc4-2f42-cfb0-c021-81c18f72851a.png)

以上で設定は完了です。

# 動作確認
ここでは index.html ファイルを更新し、パージによりキャッシュ MISS となることを確認します。
1. curl コマンドでキャッシュヒットになることを確認します。

```
$ curl -svo /dev/null http://www.example.com/lambda
...
< Age: 3
...
< X-Cache: MISS, HIT
< X-Cache-Hits: 0, 1
```
2 . s3 上の lambda ファイルを更新します
3. curl コマンドでキャッシュミスになることを確認します。

```
$ curl -svo /dev/null http://www.example.com/lambda
...
< Age: 0
...
< X-Cache: MISS, MISS
< X-Cache-Hits: 0, 0
```

4 . CloudWatch のログでも下記のように PURGE リクエストが送信されていることが確認できます。
![Screen_Shot_0029-07-18_at_22_40_08.png](https://qiita-image-store.s3.amazonaws.com/0/149542/1a5aad47-5941-30a4-9630-a7403648fffc.png)