只有累積,沒有奇蹟

2019年6月11日 星期二

[NETCore] Polly 的超時 TimeOut 和 Wrap 策略

介紹
Polly 是一套 .NET 處理瞬間故障的函式庫,提供開發人員用 Fluent API 方式及 Thread Safe 處理服務瞬間故障的策略,並提供重試(Retry)、斷路(Circuit-breaker)、超時(Timeout)、隔離(Bulkhead Isolation)、緩存(Cache)、回退(Fallback) 等機制,在上一篇 [NETCore] 使用 Polly 實現重試 (Retry) 策略 分享了 Retry 機制,這一篇就來介紹 Polly 中的 Timeout 策略,若有問題歡迎一起討論。

Timeout 策略
Polly 安裝與基本語法不再重複介紹,如果有興趣可以參考上一篇文章 : 傳送門。超時在開發中很常遇到,一般在發送 Request 到其他服務或是第三方伺服器時,都會設定 timeout 時間以避免使用者等待過久,過去在使用 httpClient 與 httpWebRequest 中可以透過 timeout 來調整等待設定,在 Polly 中設定 timeout 方式也是使用  Policy.Timeout  API 來設定逾時時間,簡單範例如下
  1. // 設定逾時時間為 10 秒
  2. Policy.Timeout(10);
  3. // async
  4. Policy.TimeoutAsync(10);
Polly 在 Timeout API 也提供多載方法方便開發者設定,同樣也可以使用 Action 方法
  1. Policy.Timeout(10, (context, timespan, task) =>
  2. {
  3. // do something , ex : log.info
  4. });
以下透過簡單範例代碼示範在 Polly 設定 Timeout 策略,在範例代碼中的 doTimeOutHTTPRequest 主要功能使用 httpclient 呼叫其他服務,為了 Demo 方便設定 timeout 時間為 3ms 讓請求出現 time exception,套用 Polly timeout 策略設定 timeout 為 1 ms,並在發生 timeout exception 時顯示 log 資訊
  1. static void Main(string[] args)
  2. {
  3. Policy
  4. .Timeout(TimeSpan.FromMilliseconds(1), onTimeout: (context, timespan, task) =>
  5. {
  6. Console.WriteLine($"{context.PolicyKey} : execution timed out after {timespan} seconds.");
  7. })
  8. .Execute(doTimeOutHTTPRequest);
  9. }
  10.  
  11. static string doTimeOutHTTPRequest()
  12. {
  13. Console.WriteLine($"開始發送 Request");
  14.  
  15. HttpResponseMessage response;
  16. using (HttpClient client = new HttpClient())
  17. {
  18. client.Timeout = TimeSpan.FromMilliseconds(3);
  19. response = client.GetAsync(" http://www.mocky.io/v2/5cfed9a23200004f0045f284").Result;
  20. }
  21.  
  22. return response.Content.ReadAsStringAsync().Result;
  23. }
執行後顯示內容如下
如果開啟 debug mode 可以看到當 1ms 沒有完成任務,會觸發 TimeoutRejectedException 異常
另外,在 Timeout 策略中可以設定 TimeoutStrategy,分為 Optimistic 與 Pessimistic 兩種設定值, 預設為 Optimistic 也就是支援發送取消 (CancellationToken),TimeoutStrategy.Optimistic 中設定 CancellationToken 代碼如下
  1. Policy timeoutPolicy = Policy.TimeoutAsync(30, TimeoutStrategy.Optimistic);
  2. HttpResponseMessage httpResponse = await timeoutPolicy
  3. .ExecuteAsync(
  4. async ct => await httpClient.GetAsync(requestEndpoint, ct),
  5. CancellationToken.None
  6. );
如果對於 TimeoutStrategy 想解瞭更多的話,可以到官方 GitHub Timeout 文章中有針對 Optimistic Timeout 與 Pessimistic Timeout 使用上更詳細的說明與範例代碼 : 傳送門

Wrap 策略
Polly 支援多個故障時的策略機制,可以因應需求來組合其故障處理策略,這也是 Polly 彈性的設計,wrap 概念就像是策略包,可以將不同的故障策略包在一起設定為遇到故障時的處理機制方法,在組合時以下語法都支援
  1. // Execute
  2. fallback.Execute(() => waitAndRetry.Execute(() => breaker.Execute(action)));
  3.  
  4. // Policy.Wrap
  5. Policy
  6. .Handle<SomeExceptionType>()
  7. .Retry(7)
  8.  
  9. // equivalently sample 1
  10. fallback.Wrap(waitAndRetry.Wrap(breaker)).Execute(action);
  11.  
  12. // equivalently sample 2
  13. fallback.Wrap(waitAndRetry).Wrap(breaker).Execute(action);
廢話不多說直接舉範例來說明,上一篇介紹了 Retry 策略這篇介紹了 Timeout 策略,我們就來結合兩個做為一個策略包,並在每個策略執行時將內容輸出在 console 上面
  1. static async Task Main(string[] args)
  2. {
  3. var timeoutPolicys = Policy
  4. .Timeout(TimeSpan.FromMilliseconds(1),
  5. onTimeout: (context, timespan, task) =>
  6. {
  7. Console.WriteLine($"{context.PolicyKey} : execution timed out after {timespan} seconds.");
  8. });
  9.  
  10. RetryPolicy waitAndRetryPolicy = Policy
  11. .Handle<Exception>()
  12. .Retry(3,
  13. onRetry: (exception, retryCount) =>
  14. {
  15. Console.WriteLine($"[Polly retry] : 呼叫 API 異常, 進行第 {retryCount} 次重試");
  16. });
  17.  
  18. FallbackPolicy<String> fallbackForTimeout = Policy<String>
  19. .Handle<TimeoutRejectedException>()
  20. .Fallback(
  21. fallbackValue: "Please try again later [Fallback for timeout]",
  22. onFallback: b => { Console.WriteLine($"這個請求超時了耶"); }
  23. );
  24.  
  25. FallbackPolicy<String> fallbackForAnyException = Policy<String>
  26. .Handle<Exception>()
  27. .Fallback(
  28. fallbackAction: () => { return "Please try again later [Fallback for any exception]"; },
  29. onFallback: e => { Console.WriteLine($"[Polly fallback] : 重試失敗, say goodbye"); }
  30. );
  31.  
  32. PolicyWrap<String> policyWrap = fallbackForAnyException.Wrap(fallbackForTimeout).Wrap(waitAndRetryPolicy)
  33. .Wrap(timeoutPolicys);
  34. policyWrap.Execute(() => doMockHTTPRequest());
  35. }
  36.  
  37. static string doMockHTTPRequest()
  38. {
  39. Console.WriteLine($"開始發送 Request");
  40.  
  41. HttpResponseMessage result;
  42. using (HttpClient client = new HttpClient())
  43. {
  44. client.Timeout = TimeSpan.FromMilliseconds(3);
  45. result = client.GetAsync("http://www.mocky.io/v2/5cfb4d9b3000006e080a8b0a").Result;
  46. }
  47.  
  48. return result.Content.ReadAsStringAsync().Result;
  49. }
執行之後輸出如下
同樣的在官網中也有提供 wrap 的範例說明 : 傳送門。 

感想
在嘗試 wrap 的過程中花了不少時間跟踩雷,Handle 定義若是指定錯誤就會不會進到指定的故障策略中,舉例來說當 Timeout 時丟出的錯誤訊息為TimeoutRejectedException,若是沒有指定到此 exception 就不會進到 retry 機制當中,或是放大絕招直接handle exeption,在 Polly 的 wrap 中使用上還是有不少眉眉角角的細節要了解,也謝謝強者同事吉米斯提醒了重要的觀念才明白,日後若有比較值得分享的應用也會在PO出來,謝謝

參考
App-vNext/Polly


Related Posts:

  • [NETCore] ASP.NET Core 建立與解析 QueryString 參數說明 之前介紹過在 .NET 中可以使用 Utility.ParseQueryString 處理 Url 中的參數,傳送門 : 使用 ParseQueryString 取得網址參數,但所使用的 System.Web 命名空間僅存在於 ASP.NET Framework 不支援 ASP.NET Core,在搜尋更好的解決方案中發現了在 ASP.NET Core 提供新的 API - QueryHelpers 可以達到同樣效果,此… Read More
  • [NETCore] ASP.NET Core 啟動失敗 - 嘗試存取通訊端被拒絕,因為存取權限不足問題  接獲同事詢問專案無法正常啟用,專案是使用 ASP.NET Core 2.2 開發並搭配 Kestrel 使用,在過去開發時都正常運作但今天忽然就遭遇啟動異常的狀況,在啟用時會跳出錯誤訊息為 'Unable to bind to http://localhost:5000 on the IPv4 loopback interface: '嘗試存取通訊端被拒絕,因為存取權限不足。''  ,這篇… Read More
  • [NETCore] 如何在 ASP.NET Core 中使用 YAML前言 今天同事在分享 ASP.NET Core 時介紹使用 YAML 作為組態設定檔,自己在過去比較少接觸 YAML 設定檔,也趁此機會來好好讓彼此熟悉一下,在 YAML 官網介紹說明文字如下 YAML is a human friendly data serialization standard for all programming languages. YAML 是一種可讀性高,適用於表達資料序列化的格式,在公司 CI… Read More
  • [NETCore] ASP.NET Core 中的排程利器 - Coravel 前言 在 ASP.NET 中相信大家都會有過開發 Scheduler 排程的需求,過去可能會使用 ASP.NET 中較有名的框架像是 Quartz.NET 或是 Hangfire,兩種框架各有優缺點小弟不才剛好都有碰過,兩種排程框架各有喜好者可以依據自己的愛好來選用。今天所要介紹的是另一套 Schedule Job 框架 Coravel,作者在設計 API 時用 Fluent interface 方式進行設計,因此在使用上相當直覺與方便… Read More
  • [NETCore] ASP.NET Core 3.0 Worker Service 搭配 Coravel 建立排程服務前言 如果一直有在 follow 消息的朋友可以發現在 ASP.NET 3.0 有新增 Work Services 專案範本,可以透過幾個簡單的步驟使用 Workers with Windows Services 服務,詳細可以參考微軟官網對於 worker Service 的介紹文章 .NET Core Workers as Windows Services,在上一篇介紹了 ASP.NET Core 中的輕量級排程… Read More

0 意見:

張貼留言

Copyright © 2025 m@rcus 學習筆記 | Powered by Blogger

Design by Anders Noren | Blogger Theme by NewBloggerThemes.com