I am trying to execute a request and return a response with 2 executers, using the Polly library with the Fallback policy. Here is my code so far:
private IExecuter primary;
private IExecuter secondary;
private readonly Policy _policy;
public Client()
{
primary = new Executer("primary");
secondary = new Executer("secondary");
_policy = Policy
.Handle<Exception>()
.Fallback((request) => GetResponseFallback(request));
}
public Response Process(Request request)
{
return _policy.Execute( GetResponse(request));
}
private Response GetResponse(Request request)
{
return this.primary.Execute(request);
}
private Response GetResponseFallback(Request request)
{
return secondary.Execute(request);
}
The problem with this code is that I can't put a Request parameter on this line:
.Fallback((request) => GetResponseFallback(request));
And the code won't compile, because of the error:
"cannot convert from 'System.Threading.CancellationToken' to 'PollyPOC.Request'"
How to make the code compile and tell the fallback policy that the action will receive a Request
parameter to the GetResponseFallback
action?
In order to pass data to your Fallback method you need to take advantage of the Context
For the sake of simplicity let me simplify your implementation a bit to show you how to use the Context
:
private int GetResponse(int request)
{
return request + 1;
}
private int GetResponseFallback(int request)
{
return request + 2;
}
So I've just get rid of the IExecuter
, Request
and Response
concepts to keep the sample code as simple as possible.
To pass data to your GetResponseFallback
we need to change the parameter like this:
private const string requestKey = "request";
private int GetResponseFallback(Context ctx)
{
var request = (int)ctx[requestKey];
return request + 2;
}
So, we have retrieved the request
data from the Context
. Now we need to somehow pass that information to the GetResponseFallback
call.
The good thing is that we don't need to modify the GetResponse
. On the other hand we need to adjust the Process
method like this:
private int Process(int request)
{
var contextData = new Dictionary<string, object> { { requestKey, request } };
_policy = Policy<int>
.Handle<Exception>()
.Fallback((ctx) => GetResponseFallback(ctx), (_, __) => { });
return _policy.Execute((_) => GetResponse(request), contextData);
}
contextData
dictionary to store the input parameter in itAction<Context> fallbackAction
parameterpublic static FallbackPolicy Fallback(this PolicyBuilder policyBuilder, Action<Context> fallbackAction, Action<Exception, Context> onFallback)
onFallback
that's why I defined that like this (_,__) => { }
public void Execute(Action<Context> action, IDictionary<string, object> contextData)
GetResponse
directly that's why we can use here the discard operator (_) => GetResponse(...)
One last important thing: I had to change the _policy
variable type to Policy<int>
to indicate the return type.
For the sake of completeness here is the full source code:
private static Policy<int> _policy;
static void Main(string[] args)
{
Console.WriteLine(Process(1));
}
private const string requestKey = "request";
static int Process(int request)
{
var contextData = new Dictionary<string, object> { { requestKey, request } };
_policy = Policy<int>
.Handle<Exception>()
.Fallback((ctx) => GetResponseFallback(ctx), (_, __) => { });
return _policy.Execute((_) => GetResponse(request), contextData);
}
static int GetResponse(int request)
{
throw new Exception();
return request + 1;
}
static int GetResponseFallback(Context ctx)
{
var request = (int)ctx[requestKey];
return request + 2;
}