You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

495 lines
16 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

namespace Polly8Study.Test
{
/// <summary>
/// Polly8超时策略 测试
/// 关键:
/// CancellationToken没有这个是不起使用的
/// 就是之前版本中的乐观超时,悲观超时貌似取消了
/// </summary>
public class Polly8TimeoutTest
{
private readonly ITestOutputHelper _output;
public Polly8TimeoutTest(ITestOutputHelper testOutput)
{
_output = testOutput;
}
/// <summary>
/// 超时策略选项
/// </summary>
[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();
}
/// <summary>
/// 非可取消任务:忽略超时
/// 同步执行
/// </summary>
[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();
}
}
/// <summary>
/// 可取消任务:超时
/// 同步执行
/// </summary>
[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();
}
}
/// <summary>
/// 可取消任务:不超时
/// 同步执行
/// </summary>
[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();
}
}
/// <summary>
/// 不可取消任务:忽略超时
/// 异步执行
/// </summary>
[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();
}
}
/// <summary>
/// 可取消任务:超时
/// 异步执行
/// </summary>
/// <returns></returns>
[Fact]
public async Task Has_CancellationToken_ExecuteAsync_Timeout_Test()
{
var pipeline = new ResiliencePipelineBuilder()
.AddTimeout(TimeSpan.FromSeconds(1))
.Build();
await Assert.ThrowsAnyAsync<Exception>(async () =>
{
var cts = new CancellationTokenSource();
await pipeline.ExecuteAsync
(
callback: async (innerToken) =>
{
//完成大约是超时的1秒多而不是任务的3秒多
await Task.Delay(1000 * 3, innerToken);
_output.WriteLine("任务执行完成");
},
cancellationToken: cts.Token
);
});
}
/// <summary>
/// 可取消任务:不超时
/// 异步执行
/// </summary>
/// <returns></returns>
[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);
}
}
// <summary>
/// 可取消任务:超时
/// 异步执行无外层Token
/// </summary>
/// <returns></returns>
[Fact]
public async Task Has_OuterCancellationToken_ExecuteAsync_Timeout_Test()
{
var pipeline = new ResiliencePipelineBuilder()
.AddTimeout(TimeSpan.FromSeconds(1))
.Build();
await Assert.ThrowsAnyAsync<Exception>(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();
}
}
/// <summary>
/// 使用CancellationToken的同步方法
/// </summary>
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();
}
}
}