Reputation: 21657
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?
Upvotes: 2
Views: 2630
Reputation: 22829
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;
}
Upvotes: 3