|
|
|
@ -0,0 +1,201 @@
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
|
|
namespace Polly8Study.Test
|
|
|
|
|
{
|
|
|
|
|
public class Polly8FallbackStrategyTest
|
|
|
|
|
{
|
|
|
|
|
private readonly ITestOutputHelper _output;
|
|
|
|
|
|
|
|
|
|
public Polly8FallbackStrategyTest(ITestOutputHelper testOutput)
|
|
|
|
|
{
|
|
|
|
|
_output = testOutput;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public async void Test()
|
|
|
|
|
{
|
|
|
|
|
FallbackStrategyOptions<int> optionsOnFallback = new FallbackStrategyOptions<int>
|
|
|
|
|
{
|
|
|
|
|
ShouldHandle = new PredicateBuilder<int>()
|
|
|
|
|
.Handle<Exception>()
|
|
|
|
|
.HandleResult(r => r > 50),
|
|
|
|
|
|
|
|
|
|
FallbackAction = static args =>
|
|
|
|
|
{
|
|
|
|
|
var v = Random.Shared.Next(1, 50);
|
|
|
|
|
return Outcome.FromResultAsValueTask(v);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
OnFallback = args =>
|
|
|
|
|
{
|
|
|
|
|
_output.WriteLine(args.Outcome.Result.ToString());
|
|
|
|
|
// Add extra logic to be executed when the fallback is triggered, such as logging.
|
|
|
|
|
return default; // Returns an empty ValueTask
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Add a fallback strategy with a FallbackStrategyOptions<TResult> instance to the pipeline
|
|
|
|
|
var pipeline = new ResiliencePipelineBuilder<int>()
|
|
|
|
|
.AddFallback(optionsOnFallback)
|
|
|
|
|
.Build();
|
|
|
|
|
|
|
|
|
|
var data = await pipeline.ExecuteAsync<int>(static async (innerToken) =>
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
return await Task.FromResult(Random.Shared.Next(1, 100));
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
_output.WriteLine(data.ToString());
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 生成回退选项
|
|
|
|
|
/// 注意:一定是有返回值的,否则没意义
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Fact]
|
|
|
|
|
public async Task Create_FallbackStrategyOption_TestAsync()
|
|
|
|
|
{
|
|
|
|
|
//以返回简单的字符串或数据为例
|
|
|
|
|
|
|
|
|
|
// 1、操作失败(异常或返回值不满足),则回退为固定值
|
|
|
|
|
var optionsSubstitute = new FallbackStrategyOptions<string>
|
|
|
|
|
{
|
|
|
|
|
//设置回退条件
|
|
|
|
|
ShouldHandle = new PredicateBuilder<string>()
|
|
|
|
|
//出现指定的异常类型时,回退
|
|
|
|
|
.Handle<Exception>()
|
|
|
|
|
//返回值满足条件时,回退
|
|
|
|
|
.HandleResult(r => r is null),
|
|
|
|
|
|
|
|
|
|
//回退时,返回的替代值
|
|
|
|
|
FallbackAction = static args => Outcome.FromResultAsValueTask("回退时的值")
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 2、如果操作失败,则回退为动态生成值
|
|
|
|
|
var optionsFallbackAction = new FallbackStrategyOptions<string>
|
|
|
|
|
{
|
|
|
|
|
//设置回退条件
|
|
|
|
|
ShouldHandle = new PredicateBuilder<string>()
|
|
|
|
|
//出现指定的异常类型时,回退
|
|
|
|
|
.Handle<Exception>()
|
|
|
|
|
//返回值满足条件时,回退
|
|
|
|
|
.HandleResult(r => r is null),
|
|
|
|
|
|
|
|
|
|
FallbackAction = static args =>
|
|
|
|
|
{
|
|
|
|
|
var text = Random.Shared.Next(100, 999).ToString();
|
|
|
|
|
return Outcome.FromResultAsValueTask(text);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 3、使用默认值或动态生成的值,如果触发回退,则执行其他操作。
|
|
|
|
|
var optionsOnFallback = new FallbackStrategyOptions<string>
|
|
|
|
|
{
|
|
|
|
|
ShouldHandle = new PredicateBuilder<string>()
|
|
|
|
|
//出现指定的异常类型时,回退
|
|
|
|
|
.Handle<Exception>()
|
|
|
|
|
//返回值满足条件时,回退
|
|
|
|
|
.HandleResult(r => r is null),
|
|
|
|
|
|
|
|
|
|
//回退时:返回替代值
|
|
|
|
|
FallbackAction = static args =>
|
|
|
|
|
{
|
|
|
|
|
var text = Random.Shared.Next(100, 999).ToString();
|
|
|
|
|
return Outcome.FromResultAsValueTask(text);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
//回退时:执行额外方法
|
|
|
|
|
OnFallback = static args =>
|
|
|
|
|
{
|
|
|
|
|
//从参数里可以拿到上下文和结果
|
|
|
|
|
Console.WriteLine(args.Outcome.Result);
|
|
|
|
|
|
|
|
|
|
// 添加在触发回退时要执行的额外逻辑,例如日志记录。
|
|
|
|
|
return default; // Returns an empty ValueTask
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 添加到弹性管道
|
|
|
|
|
var pipeline = new ResiliencePipelineBuilder<string>()
|
|
|
|
|
.AddFallback(optionsOnFallback)
|
|
|
|
|
.Build();
|
|
|
|
|
|
|
|
|
|
//使用弹性管道,执行/调用 方法
|
|
|
|
|
var data = await pipeline.ExecuteAsync<string>(static async (innerToken) =>
|
|
|
|
|
{
|
|
|
|
|
var data = Random.Shared.Next(1,100);
|
|
|
|
|
|
|
|
|
|
if (data % 0 ==0)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return await ValueTask.FromResult(data.ToString());
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
//断言
|
|
|
|
|
Assert.NotEmpty(data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 生成回退选项
|
|
|
|
|
/// 注意:一定是有返回值的,否则没意义
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Fact]
|
|
|
|
|
public async Task FallbackStrategyOption_TestAsync()
|
|
|
|
|
{
|
|
|
|
|
//方法返回 1-00 随机数,使用回退方法确保返回0-50的数据。
|
|
|
|
|
|
|
|
|
|
var optionsOnFallback = new FallbackStrategyOptions<int>
|
|
|
|
|
{
|
|
|
|
|
ShouldHandle = new PredicateBuilder<int>()
|
|
|
|
|
.Handle<Exception>()
|
|
|
|
|
.HandleResult(r => r >= 50),
|
|
|
|
|
|
|
|
|
|
//回退时:返回替代值
|
|
|
|
|
FallbackAction = args =>
|
|
|
|
|
{
|
|
|
|
|
var v = Random.Shared.Next(1, 50);
|
|
|
|
|
|
|
|
|
|
_output.WriteLine($"原方法生成的数字 {args.Outcome.Result},大于50,使用回退替代值 {v}");
|
|
|
|
|
|
|
|
|
|
return Outcome.FromResultAsValueTask(v);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
//回退时:执行额外方法(先于FallbackAction执行)
|
|
|
|
|
OnFallback = args =>
|
|
|
|
|
{
|
|
|
|
|
//从参数里可以拿到上下文和结果
|
|
|
|
|
_output.WriteLine($"回退额外方法执行,原方法生成数字为:{args.Outcome.Result}");
|
|
|
|
|
|
|
|
|
|
// 添加在触发回退时要执行的额外逻辑,例如日志记录。
|
|
|
|
|
return default; // Returns an empty ValueTask
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Add a fallback strategy with a FallbackStrategyOptions<TResult> instance to the pipeline
|
|
|
|
|
var pipeline = new ResiliencePipelineBuilder<int>()
|
|
|
|
|
.AddFallback(optionsOnFallback)
|
|
|
|
|
.Build();
|
|
|
|
|
|
|
|
|
|
var data = await pipeline.ExecuteAsync<int>(async (innerToken) =>
|
|
|
|
|
{
|
|
|
|
|
//随机返回1到100数字
|
|
|
|
|
var v = Random.Shared.Next(1, 100);
|
|
|
|
|
_output.WriteLine($"方法生成数字为:{v}");
|
|
|
|
|
|
|
|
|
|
return await Task.FromResult(v);
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
Assert.True(data <= 50);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|