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.

497 lines
17 KiB
C#

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