練習 - 實作應用程式復原
eShop 專案有兩個服務,可使用 HTTP 要求彼此通訊。 Store
服務會呼叫 Product
服務,以取得可供購買的目前所有產品清單。
應用程式的目前版本沒有復原處理。 如果 Product
服務無法使用,Store
服務會傳回錯誤給客戶,並要求他們稍後再試一次。 此行為並非良好的使用者體驗。
您的管理員要求您將復原功能新增至應用程式,讓 Store
服務在失敗時重試後端服務呼叫。
在此練習中,您會將復原功能新增至現有的雲端原生應用程式,並測試您的修正程式。
開啟開發環境
您可以選擇使用裝載本練習的 GitHub Codespace,或在 Visual Studio Code 本機上完成該練習。
若要使用 Codespace,請使用 此 Codespace 建立連結 來建立預先設定的 GitHub Codespace。
GitHub 需要幾分鐘的時間來建立及設定 Codespace。 流程完成後,您將看到該練習的程式碼檔案。 用於本課程模組其餘部分的程式碼位於 /dotnet-resiliency 目錄中。
若要使用 Visual Studio Code,請將 https://github.com/MicrosoftDocs/mslearn-dotnet-cloudnative 存放庫複製到本機電腦。 接下來:
- 安裝任何系統要求,以在 Visual Studio Code 中執行開發容器。
- 確定 Docker 是執行狀態。
- 在新的 Visual Studio Code 視窗中,開啟複製存放庫的資料夾
- 按下 Ctrl+Shift+P,以開啟命令選擇區。
- 搜尋:>開發容器:重建並在容器中重新開啟
- 從下拉式清單中選取 eShopLite - dotnet-resiliency。 Visual Studio Code 會在本機上建立您的開發容器。
建置並執行應用程式
在底部面板中,選取 [終端] 分頁,然後執行下列命令來前往程式碼根:
cd dotnet-resiliency
執行下列命令以組建 eShop 應用程式映像:
dotnet publish /p:PublishProfile=DefaultContainer
組建完成後,執行下列命令以啟動應用程式:
docker compose up
在底部面板中,選取 [連接埠] 索引標籤,然後在資料表的 [轉寄位址] 資料行中,選取 [前端 (32000)] 連接埠的 [在瀏覽器中開啟] 圖示。
如果您在本機執行應用程式,請開啟瀏覽器視窗以檢視
http://localhost:32000/products
。eShop 應用程式應該正在執行。 選取 [產品] 功能表項目,您應該會看到產品清單。
測試目前的復原能力
停止產品服務,以查看應用程式發生什麼情況。
返回您的 Codespace,然後在 [終端機] 索引標籤中選取 + 以開啟新的 Bash 終端機。
執行下列 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
尋找 productservice 容器的容器識別碼。 在上述範例中,識別碼為 6ba80f3c7ab0。
使用下列 Docker 命令停止您的產品服務:
docker stop <CONTAINER ID>
其中
<CONTAINER ID>
是您在上一個步驟中找到的識別碼。 例如:docker stop 6ba80f3c7ab0
返回執行應用程式的瀏覽器索引標籤,然後重新整理頁面。 您應該會看到錯誤訊息:
載入產品時發生問題。 請稍後再試一次。
返回您的 Codespace,然後在 [終端] 中選取 [Docker] 終端,並按 Ctrl+C 以停止應用程式。 您應該會看到:
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 套件
在您的 Codespace 中,於 [終端機] 索引標籤上,瀏覽至 [市集] 專案資料夾:
cd Store
執行下列命令以新增復原 NuGet 套件:
dotnet add package Microsoft.Extensions.Http.Resilience
從應用程式專案資料夾中的終端執行此命令,會將套件參考新增至 Store.csproj 專案檔。
在 [總管] 提要欄位中,選取 [Program.cs]。
在檔案頂端新增下列 using 陳述式:
using Microsoft.Extensions.Http.Resilience;
新增標準復原策略
在第 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。 此處理常式會使用標準復原策略的所有預設設定。
您的應用程式不需要進行任何其他程式碼變更。 現在來執行應用程式並測試復原功能。
執行下列命令以重建 eShop 應用程式:
cd .. dotnet publish /p:PublishProfile=DefaultContainer
組建完成後,執行下列命令以啟動應用程式:
docker compose up
返回執行應用程式的瀏覽器索引標籤,然後重新整理產品頁面。 您應該會看到產品清單。
返回您的 Codespace,然後在 [終端機] 索引標籤中選取第二個 Bash 終端機。 複製 productservice 容器的容器識別碼。
重新執行 docker stop 命令:
docker stop <CONTAINER ID>
返回執行應用程式的瀏覽器索引標籤,然後重新整理產品頁面。 這一次應該會花費稍微久的時間,您才會看到應用程式錯誤訊息:
載入產品時發生問題。 請稍後再試一次。
讓我們檢查記錄,以查看我們的復原策略是否正常運作。
返回您的 Codespace,然後在 [終端機] 索引標籤中選取 [Docker] 終端機。
在終端中,按 Ctrl+C 以停止執行中的應用程式。
在記錄訊息中,向上捲動直到您找到 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'
您應該會看到許多類似這樣的訊息,每個訊息都是重試嘗試。 上述訊息會顯示第二次嘗試,以及執行所花費的時間。
設定復原策略
當您將復原功能新增至應用程式時,您會平衡快速回應使用者的需求,而不需要多載任何後端服務。 只有您可以決定預設選項是否符合您的企業需求。
在此範例中,您想要讓市集服務等候更久的時間,讓市集服務有機會復原。
在 Program.cs 的程式碼視窗中,將第 13 行的程式碼變更為:
.AddStandardResilienceHandler(options => { options.Retry.MaxRetryAttempts = 7; });
上述程式碼會變更重試策略預設值,使重試次數上限為 7。 請記住,策略是指數輪詢,因此總時間約為 5 分鐘。
使用 Ctrl+C 停止 Docker。 然後執行下列命令以重建 eShop 應用程式:
dotnet publish /p:PublishProfile=DefaultContainer
組建完成後,執行下列命令以啟動應用程式:
docker compose up
停止 Bash 終端中的後端服務容器,並重新整理 eShop。 請注意,錯誤訊息需要較長的時間才會顯示。 如果您檢查記錄,可以看到重試策略只重試五次。 Polly 的最後一則訊息為:
Polly.Timeout.TimeoutRejectedException: The operation didn't complete within the allowed timeout of '00:00:30'.
上述訊息告訴您,要求逾時總計會避免達到重試次數上限。 您可以藉由增加要求逾時總計來修正此問題。
在終端,按 Ctrl+C 以停止應用程式。
在 Program.cs 的程式碼視窗中,將第 13 行的程式碼變更為:
.AddStandardResilienceHandler(options => { options.Retry.RetryCount = 7; options.TotalRequestTimeout = new HttpTimeoutStrategyOptions { Timeout = TimeSpan.FromMinutes(5) }; });
上述程式碼會將要求逾時總計變更為 260 秒,現在比重試策略還久。
經過這些變更,您應該有足夠的時間執行應用程式、停止產品服務、檢查終端記錄中是否有重試嘗試、重新整理 eShop 以查看載入訊息,最後重新啟動產品服務以成功查看產品清單。
執行下列命令以重建 eShop 應用程式:
dotnet publish /p:PublishProfile=DefaultContainer
組建完成後,執行下列命令以啟動應用程式:
docker compose up
測試新的復原選項
若要協助測試容器中的應用程式,請使用 Docker 擴充功能。 擴充功能可提供 GUI,用以檢視及控制容器的狀態。