namespace Polly8Study.Test
{
///
/// Polly8超时策略 测试
/// 关键:
/// CancellationToken,没有这个是不起使用的
/// 就是之前版本中的乐观超时,悲观超时貌似取消了
///
public class Polly8TimeoutStrategyTest
{
private readonly ITestOutputHelper _output;
public Polly8TimeoutStrategyTest(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();
}
}
}