[アップデート] AWS Amplify Hosting に追加された「スキュー保護」を試してみた
いわさです。
AWS Amplify の先日のアップデートでブランチに対して「スキュー保護」を設定できるようになりました。
バージョンスキューなど言われたりしますが、マイクロサービス間だったりクライアント・サーバーだったり、バージョン間の違いによってアプリケーションが意図せぬ挙動を行う場合があります。
今回の AWS Amplify のアップデートはクライアントとサーバーのバージョンスキューの発生を保護する仕組みです。
今回バージョンスキューを発生させたり、スキュー保護を行って挙動の確認などを行ってみました。
これまでデプロイのタイミングで実行バージョンのズレは起きうるよなぁとは思っていたのですが、こういう形で機能的に保護することができるのだなと学びになりました。
バージョンスキューを発生させる
まずはバージョンスキューを発生させます。
今回の機能を有効化できるのは静的ホスティングあるいは SSR アプリケーションとのことなので、サーバーサイドに非同期でアセットを取得しにいく単純な HTML ファイルを作成してみました。[1]
<!DOCTYPE html>
<html>
<head>
    <title>Content Loader</title>
</head>
<body>
    <button onclick="loadContent()">Load Content</button>
    <div id="imageContainer"></div>
    <script src="app.js"></script>
</body>
</html>
function loadContent() {
    fetch('content.txt')
        .then(response => {
            if (!response.ok) {
                throw new Error('Could not obtain content.txt');
            }
            return response.text();
        })
        .then(text => {
            const container = document.getElementById('imageContainer');
            container.innerHTML = '';
            container.innerHTML = text;
        })
        .catch(error => {
            console.error('Error loading content:', error);
            const container = document.getElementById('imageContainer');
            container.innerHTML = 'content.txt could not be obtained';
        });
}
今回は、これらを Amazon S3 バケットへアップロードし、以下の機能を使って Amplify へデプロイしました。
余談ですが、改めてこのデプロイ機能めっちゃ楽だなと思いました。リクエスト単価が少しだけ高くなるのだけど、CloudFront + S3 よりつらみが解消されていたり何より楽なので推していきたいです。
デプロイ後にアプリの動作確認をしてみましょう。
画面にボタンがひとつ設置されています。

これを押すと、HTML や JavaScript と同時に設置しているサーバーサイドアセットcontent.txtを取得して画面に描画する、という挙動をします。

この時、クライアントでページを表示させた後にサーバーコンテンツを変更するデプロイが発生しcontent.txtが削除されたものがデプロイされた場合どうなるでしょうか。
通常であればコンテンツの削除にともなって HTML や JavaScript も修正されるべきですが、クライアントブラウザにロードされた HTML はリロードしない限りは更新されません。
そのためこういったデプロイが発生した際に、ロード済みクライアントでサーバーサイドにアクセスしようとするとエラーが発生します。
今回のアプリケーションであればcontent.txtの取得に失敗しました。

かなり単純化してますが、これがバージョンスキューの挙動です。
スキュー保護を有効化する
ではここで今回のアップデートである「スキュー保護」機能を有効化してみましょう。
なお、有効化の公式ドキュメントは以下となります。
デフォルトではスキュー保護は無効化されており、デプロイ済みのアプリケーションに対して有効化が必要です。追加料金は発生しません。
スキュー保護はブランチ設定から確認・設定が出来ます。

この機能はブランチごとに有効化するもので、ブランチを選択しアクションメニューの「スキュー保護を有効にする」を選択します。

以下は確認ダイアログです。
スキュー保護が有効化されると過去のデプロイコンテンツが保持され、古いクライアントからは適切なバージョンにアクセスされるようになります。
通常のアプリケーションでは過去 8 回のデプロイバージョンが保護されます。静的アプリケーションの場合は 1 週間が保護期間となります。

なお、有効化後にデプロイする必要がありまして、その初回のデプロイは通常よりも時間がかかります。
今回のような最小の静的ホスティング構成の場合は通常デプロイが 8 秒くらいなのですが、スキュー保護の有効化後は 2 分 46 秒かかりました。

ただ、初回のデプロイ以降はまた 8 秒でデプロイできるようになったので、初回だけ時間がかかるよという点を覚えておきましょう。
バージョン確認
さて、スキュー保護を有効化してデプロイが出来たのでバージョンスキューの動作確認をしてみます。
このスキュー保護ですが、デフォルトでは Cookie を使ってバージョンの振り分けが行われるようになっています。
スキュー有効化後は_dplというレスポンス Cookie が使われていることが確認できました。

今回はこのデフォルトの Cookie での挙動を確認しますが、X-Amplify-Dpl ヘッダーや dpl クエリパラメータを使うことも出来ます。Cookie の制御だと都合が悪い場合はより高度なカスタマイズをしたい場合は、明示的な実装が必要になりますがそちらを使いましょう。
ブラウザで HTML と JavaScript を読み込み後、次のように S3 バケットのコンテンツを更新しました。

また、Amplify ホスティングは S3 バケットをオリジンにしているわけではなく、デプロイのためのアセット格納先というだけなので、Amplify 側でもデプロイ操作が必要です。

デプロイ出来ました。
ここでサーバーアセットを読み込むボタンを押してみましょう。
content.txtが存在しないので、先程までは読み込みに失敗するケースです。

読み込むことが出来ましたね。
最新のデプロイにはcontent.txtが含まれていないですが、クライアントバージョンと一致するデプロイバージョンが保持されており、Cookie によってそのバージョンからコンテンツが取得されています。
ためしにリロードして Cookie を新しいものにしてみると、コンテンツ取得に失敗しました。なるほど。

さいごに
本日は AWS Amplify Hosting に追加された「スキュー保護」を試してみました。
これまでデプロイ時の課題として感じていた部分だったのですが、こういったマネージドな機能で対処することができるんですね。おもしろい。
追加コストもかからないということなので使いやすそうです。







