演習 - アプリケーションの回復性を実装する

完了

eShop プロジェクトには、HTTP 要求を使用して相互に通信する 2 つのサービスがあります。 Store サービスは、Product サービスを呼び出して、購入可能なすべての現在の製品の一覧を取得します。

現在のバージョンのアプリには回復性の処理がありません。 Product サービスが使用できない場合、Store サービスは顧客にエラーを返し、後でもう一度やり直すように求めます。 この動作は、優れたユーザー エクスペリエンスではありません。

Store サービスが失敗した場合にバックエンド サービスの呼び出しを再試行するように、マネージャーからアプリに回復性を追加するよう求められます。

この演習では、既存のクラウドネイティブ アプリに回復性を追加し、修正プログラムをテストします。

開発環境を開く

演習をホストする GitHub codespace を使うか、Visual Studio Code でローカルで演習を完了するかを選択できます。

コードスペースを使用するには、この Codespace 作成リンクを使用して、事前構成済みの GitHub Codespace を作成します

GitHub では、コードスペースの作成と構成に数分かかります。 プロセスが完了すると、演習のコード ファイルが表示されます。 このモジュールの残りの部分で使用するコードは 、/dotnet-resiliency ディレクトリにあります。

Visual Studio Code を使用するには、ローカル コンピューターに https://github.com/MicrosoftDocs/mslearn-dotnet-cloudnative リポジトリをクローンします。 その後、以下を実行します。

  1. Visual Studio Code で Dev Container を実行するためのシステム要件をインストールします。
  2. Docker が動作していることを確認します。
  3. 新しい Visual Studio Code ウィンドウで、クローンされたリポジトリのフォルダーを開きます
  4. Ctrl+Shift+P キーを押して、コマンド パレットを開きます。
  5. 検索: >開発コンテナ: コンテナーで再構築して再度開く
  6. ドロップダウンから eShopLite - dotnet-resiliency を選択します。 Visual Studio Code により、ローカルで開発コンテナーが作成されます。

アプリをビルドして実行する

  1. 下部のパネルで、[ ターミナル ] タブを選択し、次のコマンドを実行してコード ルートに移動します。

    cd dotnet-resiliency
    
  2. 次のコマンドを実行して、eShop アプリ イメージをビルドします。

    dotnet publish /p:PublishProfile=DefaultContainer
    
  3. ビルドが完了したら、次のコマンドを実行してアプリを起動します。

    docker compose up
    
  4. 下部のパネルで、[ポート] タブを選択し、テーブルの [転送先アドレス] 列で、フロントエンド (32000) ポートの [ブラウザーで開く] アイコンを選択します。

    アプリをローカルで実行している場合は、ブラウザー ウィンドウを開いて http://localhost:32000/products表示します。

  5. eShop アプリが実行されている必要があります。 [ 製品 ] メニュー項目を選択すると、製品の一覧が表示されます。

    ブラウザーで実行されている eShop アプリを示すスクリーンショット。

現在の回復性をテストする

製品サービスを停止して、アプリの動作を確認します。

  1. コードスペースに戻り、[ ターミナル ] タブで + を選択して新しい bash ターミナルを開きます。

  2. 次の docker コマンドを実行して、実行中のコンテナーを一覧表示します。

    docker ps
    

    現在実行中のコンテナーの一覧が表示されます。次に例を示します。

    CONTAINER ID   IMAGE                                                                            COMMAND                  CREATED          STATUS          PORTS                                                        NAMES
    c08285e8aaa4   storeimage                                                                       "dotnet Store.dll"       8 minutes ago    Up 8 minutes    80/tcp, 443/tcp, 0.0.0.0:5902->8080/tcp, :::5902->8080/tcp   eshoplite-frontend-1
    6ba80f3c7ab0   productservice                                                                   "dotnet Products.dll"    8 minutes ago    Up 8 minutes    80/tcp, 443/tcp, 0.0.0.0:5200->8080/tcp, :::5200->8080/tcp   eshoplite-backend-1
    cd0c822a5222   vsc-eshoplite-958868d22c9851dd911b2423199bfc782861d1a8f7afac48e5096a1b7516082f   "/bin/sh -c 'echo Co…"   27 minutes ago   Up 27 minutes     
    
  3. productservice コンテナーの CONTAINER ID を探します。 上記の例では、ID は 6ba80f3c7ab0 です

  4. 次の docker コマンドを使用して製品サービスを停止します。

    docker stop <CONTAINER ID>
    

    ここで、 <CONTAINER ID> は前の手順で見つけた ID です。 例えば次が挙げられます。

    docker stop 6ba80f3c7ab0
    
  5. アプリを実行しているブラウザー タブに戻り、ページを更新します。 次のエラー メッセージが表示されます。

    製品の読み込みに問題があります。 後でもう一度やり直してください。

  6. コードスペースに戻り、ターミナルDocker ターミナルを選択し、Ctrl+キーを押してアプリを停止します。 次のような結果が表示されます。

    Gracefully stopping... (press Ctrl+C again to force)
    Aborting on container exit...
    [+] Stopping 2/1
     ✔ Container eshoplite-frontend-1  Stopped                                                                      0.3s 
     ✔ Container eshoplite-backend-1   Stopped                                                                      0.0s 
    canceled
    

アプリに回復性を追加する

アプリの回復力を高める最初の手順は、 Microsoft.Extensions.Http.Resilience NuGet パッケージをプロジェクトに追加することです。 その後、 Program.csで使用できます。

Microsoft.Extensions.Http.Resilience パッケージを追加する

  1. コードスペースの [ターミナル ] タブで、 ストア プロジェクト フォルダーに移動します。

    cd Store
    
  2. 次のコマンドを実行して、回復性 NuGet パッケージを追加します。

    dotnet add package Microsoft.Extensions.Http.Resilience
    

    アプリ プロジェクト フォルダーのターミナルからこのコマンドを実行すると、パッケージ参照が Store.csproj プロジェクト ファイルに追加されます。

  3. [エクスプローラー] サイドバーで、Program.csを選択します。

  4. ファイルの先頭に、次の using ステートメントを追加します。

    using Microsoft.Extensions.Http.Resilience;
    

標準の回復性戦略を追加する

  1. 行 13 の ;の前に、次のコードを追加します。

    .AddStandardResilienceHandler()
    

    コードは次のようになります。

    builder.Services.AddHttpClient<ProductService>(c =>
    {
        var url = builder.Configuration["ProductEndpoint"] ?? throw new InvalidOperationException("ProductEndpoint is not set");
    
        c.BaseAddress = new(url);
    }).AddStandardResilienceHandler();
    

    上記のコードは、HTTPClient に標準の回復性ハンドラーを追加します。 ハンドラーは、標準の回復性戦略のすべての既定の設定を使用します。

    アプリに他のコード変更は必要ありません。 アプリを実行し、回復性をテストしましょう。

  2. 次のコマンドを実行して、eShop アプリをリビルドします。

    cd ..
    dotnet publish /p:PublishProfile=DefaultContainer
    
  3. ビルドが完了したら、次のコマンドを実行してアプリを起動します。

    docker compose up
    
  4. アプリを実行しているブラウザー タブに戻り、製品ページを更新します。 製品の一覧が表示されます。

  5. コードスペースに戻り、[ ターミナル ] タブで 2 番目の bash ターミナルを選択します。 productservice コンテナーの CONTAINER ID をコピーします。

  6. docker stop コマンドを再実行します。

    docker stop <CONTAINER ID>
    
  7. アプリを実行しているブラウザー タブに戻り、製品ページを更新します。 今回は、アプリのエラー メッセージが表示されるまで少し時間がかかります。

    製品の読み込みに問題があります。 後でもう一度やり直してください。

    ログを確認して、回復性戦略が機能しているかどうかを確認しましょう。

  8. コードスペースに戻り、[ ターミナル ] タブで Docker ターミナルを選択します。

  9. ターミナルで Ctrl+キーを押して、アプリの実行を停止します。

  10. ログ メッセージで、 Polly への参照が見つかるまで上にスクロールします。

    eshoplite-frontend-1  | warn: Polly[3]
    eshoplite-frontend-1  |       Execution attempt. Source: 'ProductService-standard//Standard-Retry', Operation Key: '', Result: 'Name or service not known (backend:8080)', Handled: 'True', Attempt: '2', Execution Time: '27.2703'
    

    このようなメッセージが多数表示されます。それぞれ再試行です。 上記のメッセージは、2 回目の試行と実行にかかった時間を示しています。

回復性戦略を構成する

アプリに回復性を追加すると、ユーザーに迅速に対応する必要性と、バックエンド サービスをオーバーロードしない必要性のバランスが取られます。 既定のオプションがビジネス ニーズを満たしているかどうかを判断できるのは、あなただけです。

この例では、ストア サービスが回復する機会を与えるために、ストア サービスを少し長く待機させます。

  1. Program.csのコード ウィンドウで、13 行目のコードを次のコードに変更します。

    .AddStandardResilienceHandler(options =>
    {
        options.Retry.MaxRetryAttempts = 7;
    });
    

    上記のコードでは、再試行戦略の既定値が最大リタイア数が 7 に変更されています。 戦略は指数バックオフなので、合計時間は約 5 分です。

  2. + を使用して Docker を停止します。 次に、次のコマンドを実行して eShop アプリをリビルドします。

    dotnet publish /p:PublishProfile=DefaultContainer
    
  3. ビルドが完了したら、次のコマンドを実行してアプリを起動します。

    docker compose up
    

    bash ターミナルでバックエンド サービス コンテナーを停止し、eShop を更新します。 エラー メッセージが表示されるまでに時間がかかることに注意してください。 ただし、ログを確認すると、再試行戦略が 5 回だけ再試行されたことがわかります。 Polly からの最後のメッセージは次のとおりです。

    Polly.Timeout.TimeoutRejectedException: The operation didn't complete within the allowed timeout of '00:00:30'.
    

    上記のメッセージは、合計要求タイムアウトによる停止で、最大再試行回数に達しなかったことを示しています。 要求の合計タイムアウトを増やすことで、この問題を解決できます。

  4. ターミナルで Ctrl+キーを押してアプリを停止します。

  5. Program.csのコード ウィンドウで、13 行目のコードを次のコードに変更します。

    .AddStandardResilienceHandler(options =>
    {
        options.Retry.RetryCount = 7;
        options.TotalRequestTimeout = new HttpTimeoutStrategyOptions
        {
            Timeout = TimeSpan.FromMinutes(5)
        };
    });
    

    上記のコードでは、要求の合計タイムアウトが 260 秒に変更されます。これは、再試行戦略よりも長くなっています。

    これらの変更により、アプリの実行、製品サービスの停止、再試行のターミナル ログの確認、eShop の更新による読み込みメッセージの確認、製品サービスの再起動によって製品の一覧が正常に表示されるようにするのに十分な時間が必要になります。

  6. 次のコマンドを実行して、eShop アプリをリビルドします。

    dotnet publish /p:PublishProfile=DefaultContainer
    
  7. ビルドが完了したら、次のコマンドを実行してアプリを起動します。

    docker compose up
    

新しい回復性オプションをテストする

コンテナー内のアプリをテストするには、Docker 拡張機能を使用します。 拡張機能は、コンテナーの状態を表示および制御するための GUI を提供します。

  1. 左側のメニューから、 Docker アイコンを選択します。

    製品サービスを停止する方法を示す Docker 拡張機能のスクリーンショット。

  2. DOCKER パネルの [コンテナー] で、製品コンテナーを右クリックし、[停止] を選択します。

  3. アプリを実行しているブラウザー タブに戻り、製品ページを更新します。 読み込み中... メッセージが表示されます。

  4. コードスペースに戻り、[ ターミナル ] タブで Docker ターミナルを選択します。 回復性戦略が機能しています。

  5. DOCKER パネルの [コンテナー] で、製品コンテナーを右クリックし、[開始] を選択します

  6. アプリを実行しているブラウザー タブに戻ります。 待機すると、アプリは製品の一覧を表示して回復する必要があります。

  7. ターミナルで、C を使用して docker を停止+。