namespace Polly8Study.Test { /// /// Polly8超时策略 测试 /// 关键: /// CancellationToken,没有这个是不起使用的 /// 就是之前版本中的乐观超时,悲观超时貌似取消了 /// public class Polly8TimeoutTest { private readonly ITestOutputHelper _output; public Polly8TimeoutTest(ITestOutputHelper testOutput) { _output = testOutput; } /// /// 超时策略选项 /// [Fact] public void TimeoutStrategyOptions_Test() { //直接设置 new ResiliencePipelineBuilder() .AddTimeout(TimeSpan.FromMilliseconds(100)) .Build(); //默认值 var defaultOption = new TimeoutStrategyOptions(); //全功能 TimeoutStrategyOptions timeoutOption = new TimeoutStrategyOptions { //名称唯一标识了特定策略的特定实例,也包含在由各个弹性策略生成的遥测数据中 Name = "timeout", //固定超时时间(启用了TimeoutGenerator,则无效) Timeout = TimeSpan.FromSeconds(2), //动态超时时间设置 //TimeoutGenerator = arg => //{ // var ts = TimeSpan.FromSeconds(Math.Pow(2, 1)); // return ValueTask.FromResult(ts); //}, //发生超时时引发的超时委托 OnTimeout = (args) => { var key = args.Context.OperationKey; _output.WriteLine("OnTimeout"); return ValueTask.CompletedTask; }, }; //使用 ResiliencePipeline pipeline = new ResiliencePipelineBuilder() .AddTimeout(timeoutOption) .Build(); } /// /// 非可取消任务:忽略超时 /// 同步执行 /// [Fact] public void No_CancellationToken_Test() { ResiliencePipeline pipeline = new ResiliencePipelineBuilder() .AddTimeout(TimeSpan.FromSeconds(1)) .Build(); //外部tcs可省略 var tcs = new CancellationTokenSource(); try { pipeline.Execute ( //此处必须是可取消的任务,否则超时不作为(一直等待) callback: (CancellationToken innerToken) => { //虽然接口耗时大,因为没有使用‘可取消的’ Send请求,超时设置被忽略,会等待接口正确返回 HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, "http://localhost:44344/api/Timeout/Slow"); //关键:Send方法 没有传入参数 cancellationToken //其它同步方法,只要是可取消方法均可 HttpResponseMessage response = new HttpClient().Send(requestMessage); if (response.IsSuccessStatusCode == false) { _output.WriteLine($"非正常响应,响应码:{response.StatusCode}"); return; } var stream = response.Content.ReadAsStream(); var bs = new byte[stream.Length]; stream.Read(bs, 0, (int)stream.Length); var text = System.Text.UTF8Encoding.UTF8.GetString(bs); _output.WriteLine($"响应内容:{text}"); _output.WriteLine("任务执行完成"); }, cancellationToken: tcs.Token ); } catch (OperationCanceledException ex) { _output.WriteLine($"任务取消,引发异常:{ex.Message}"); } catch (TimeoutRejectedException ex) { _output.WriteLine($"超时,引发异常:{ex.Message}"); } catch (Exception ex) { _output.WriteLine($"API服务异常:{ex.Message}"); } finally { tcs.TryReset(); } } /// /// 可取消任务:超时 /// 同步执行 /// [Fact] public void Has_CancellationToken_Timeout_Test() { TimeoutStrategyOptions timeoutOption = new TimeoutStrategyOptions { //名称唯一标识了特定策略的特定实例,也包含在由各个弹性策略生成的遥测数据中 Name = "timeout", //固定超时时间(启用了TimeoutGenerator,则无效) Timeout = TimeSpan.FromSeconds(1), //动态超时时间设置 //TimeoutGenerator = arg => //{ // var ts = TimeSpan.FromSeconds(Math.Pow(2, 1)); // return ValueTask.FromResult(ts); //}, //发生超时时引发的超时委托 OnTimeout = (args) => { _output.WriteLine("OnTimeout 超时委托执行"); return ValueTask.CompletedTask; }, }; ResiliencePipeline pipeline = new ResiliencePipelineBuilder() .AddTimeout(timeoutOption) .Build(); var tcs = new CancellationTokenSource(); try { pipeline.Execute ( //此处必须是可取消的任务,否则超时不作为(一直等待) callback: (innerToken) => { HttpRequestMessage r = new HttpRequestMessage(HttpMethod.Get, "http://localhost:44344/api/Timeout/Slow"); var response = new HttpClient().Send(r, innerToken); if (response.IsSuccessStatusCode == false) { Console.WriteLine("非正常响应"); return; } var stream = response.Content.ReadAsStream(); var bs = new byte[stream.Length]; stream.Read(bs, 0, (int)stream.Length); var text = System.Text.UTF8Encoding.UTF8.GetString(bs); _output.WriteLine($"响应内容:{text}"); _output.WriteLine("任务执行完成"); }, cancellationToken: tcs.Token ); } catch (OperationCanceledException ex) { _output.WriteLine($"任务取消,引发异常:{ex.Message}"); } catch (TimeoutRejectedException ex) { _output.WriteLine($"超时,引发异常:{ex.Message}"); } catch (Exception ex) { _output.WriteLine($"API服务异常:{ex.Message}"); } finally { tcs.TryReset(); } } /// /// 可取消任务:不超时 /// 同步执行 /// [Fact] public void Has_CancellationToken_NotTimeout_Test() { TimeoutStrategyOptions timeoutOption = new TimeoutStrategyOptions { //名称唯一标识了特定策略的特定实例,也包含在由各个弹性策略生成的遥测数据中 Name = "timeout", //固定超时时间(启用了TimeoutGenerator,则无效) Timeout = TimeSpan.FromSeconds(5), //动态超时时间设置 //TimeoutGenerator = arg => //{ // var ts = TimeSpan.FromSeconds(Math.Pow(2, 1)); // return ValueTask.FromResult(ts); //}, //发生超时时引发的超时委托 OnTimeout = (args) => { Console.WriteLine("OnTimeout 超时委托执行"); return ValueTask.CompletedTask; }, }; ResiliencePipeline pipeline = new ResiliencePipelineBuilder() .AddTimeout(timeoutOption) .Build(); var tcs = new CancellationTokenSource(); try { pipeline.Execute ( //此处必须是可取消的任务,否则超时不作为(一直等待) callback: (innerToken) => { HttpRequestMessage r = new HttpRequestMessage(HttpMethod.Get, "http://localhost:44344/api/Timeout/Slow"); var response = new HttpClient().Send(r, innerToken); if (response.IsSuccessStatusCode == false) { Console.WriteLine("非正常响应"); return; } var stream = response.Content.ReadAsStream(); var bs = new byte[stream.Length]; stream.Read(bs, 0, (int)stream.Length); var text = System.Text.UTF8Encoding.UTF8.GetString(bs); _output.WriteLine($"响应内容:{text}"); _output.WriteLine("任务执行完成"); }, cancellationToken: tcs.Token ); } catch (OperationCanceledException ex) { _output.WriteLine($"任务取消,引发异常:{ex.Message}"); } catch (TimeoutRejectedException ex) { _output.WriteLine($"超时,引发异常:{ex.Message}"); } catch (Exception ex) { _output.WriteLine($"API服务异常:{ex.Message}"); } finally { tcs.TryReset(); } } /// /// 不可取消任务:忽略超时 /// 异步执行 /// [Fact] public async void No_CancellationToken_ExecuteAsync_Test() { TimeoutStrategyOptions timeoutOption = new TimeoutStrategyOptions { //名称唯一标识了特定策略的特定实例,也包含在由各个弹性策略生成的遥测数据中 Name = "timeout", //固定超时时间(启用了TimeoutGenerator,则无效) Timeout = TimeSpan.FromSeconds(1), //发生超时时引发的超时委托 OnTimeout = (args) => { _output.WriteLine("OnTimeout 超时委托执行"); return ValueTask.CompletedTask; }, }; ResiliencePipeline pipeline = new ResiliencePipelineBuilder() .AddTimeout(timeoutOption) .Build(); var tcs = new CancellationTokenSource(); try { await pipeline.ExecuteAsync ( //此处为不可取消的任务,忽略超时(会一直等待) callback: async (innerToken) => { //完成大约是2秒多,而不是超时的1秒多 await Task.Delay (1000*3); _output.WriteLine("任务执行完成"); }, cancellationToken: tcs.Token ); } catch (OperationCanceledException ex) { _output.WriteLine($"任务取消,引发异常:{ex.Message}"); } catch (TimeoutRejectedException ex) { _output.WriteLine($"超时,引发异常:{ex.Message}"); } catch (Exception ex) { _output.WriteLine($"API服务异常:{ex.Message}"); } finally { tcs.TryReset(); } } /// /// 可取消任务:超时 /// 异步执行 /// /// [Fact] public async Task Has_CancellationToken_ExecuteAsync_Timeout_Test() { var pipeline = new ResiliencePipelineBuilder() .AddTimeout(TimeSpan.FromSeconds(1)) .Build(); await Assert.ThrowsAnyAsync(async () => { var cts = new CancellationTokenSource(); await pipeline.ExecuteAsync ( callback: async (innerToken) => { //完成大约是超时的1秒多,而不是任务的3秒多 await Task.Delay(1000 * 3, innerToken); _output.WriteLine("任务执行完成"); }, cancellationToken: cts.Token ); }); } /// /// 可取消任务:不超时 /// 异步执行 /// /// [Fact] public async Task Has_CancellationToken_ExecuteAsync_NoTimeout_Test() { var pipeline = new ResiliencePipelineBuilder() .AddTimeout(TimeSpan.FromSeconds(3)) .Build(); try { var cts = new CancellationTokenSource(); await pipeline.ExecuteAsync ( callback: async (innerToken) => { //不超时,完成大约是任务耗时的1秒 await Task.Delay(1000, innerToken); _output.WriteLine("任务执行完成"); }, cancellationToken: cts.Token ); } catch (Exception ex) { _output.WriteLine(ex.Message); } } // /// 可取消任务:超时 /// 异步执行,无外层Token /// /// [Fact] public async Task Has_OuterCancellationToken_ExecuteAsync_Timeout_Test() { var pipeline = new ResiliencePipelineBuilder() .AddTimeout(TimeSpan.FromSeconds(1)) .Build(); await Assert.ThrowsAnyAsync(async () => { await pipeline.ExecuteAsync ( callback: async (innerToken) => { //完成大约是超时的1秒多,而不是任务的3秒多 await Task.Delay(1000 * 3, innerToken); _output.WriteLine("任务执行完成"); } ); }); } [Fact] public void SyncWithCancellationToken_Test() { ResiliencePipeline pipeline = new ResiliencePipelineBuilder() .AddTimeout(TimeSpan.FromSeconds(3)) .Build(); var tcs = new CancellationTokenSource(); try { pipeline.Execute ( //此处必须是可取消的任务,否则超时不作为(一直等待) callback: SyncWithCancellationToken, cancellationToken: tcs.Token ); } catch (OperationCanceledException ex) { _output.WriteLine($"任务取消,引发异常:{ex.Message}"); } catch (TimeoutRejectedException ex) { _output.WriteLine($"超时,引发异常:{ex.Message}"); } catch (Exception ex) { _output.WriteLine($"API服务异常:{ex.Message}"); } finally { tcs.TryReset(); } } /// /// 使用CancellationToken的同步方法 /// private void SyncWithCancellationToken(CancellationToken cancellationToken) { Thread thread = new Thread((token) => { int max = 500; while (max > 0) { if (cancellationToken.IsCancellationRequested) { break; } max -= 1; Thread.Sleep(10); } }); thread.Start(); thread.Join(); } } }