Polly
Polly copied to clipboard
Using class with generic parameter in RetryPolicy<T>
Summary: What are you wanting to achieve?
I am trying to use RetryPolicy with generic parameter that can contain class with another generic parameter, for example, because they share same logic
RetryPolicy<ApiTaskResult<DraftsBuilderBuildResult>>
RetryPolicy<ApiTaskResult<CheckResult>>
RetryPolicy<ApiTaskResult<PrepareResult>>
RetryPolicy<ApiTaskResult<Docflow>>
What code or approach do you have so far?
private readonly RetryPolicy<ApiTaskResult<DraftsBuilderBuildResult>> _taskCheckDraftsBuilderBuildResultQueryingRetryPolicy = Policy
.Handle<Exception>()
.OrResult<ApiTaskResult<DraftsBuilderBuildResult>>(r => r.TaskState == TaskState.Running)
.WaitAndRetry(
50,
rc => TimeSpan.FromSeconds(5 * rc),
(driven, span) =>
{
Debug.WriteLine(driven.Exception is null
? $"Task {driven.Result.Id} is still running, waiting {span.TotalSeconds} seconds."
: $"{driven.Exception}, waiting {span.TotalSeconds} seconds.");
});
private readonly RetryPolicy<ApiTaskResult<CheckResult>> _taskCheckDraftsCheckResultQueryingRetryPolicy = Policy
.Handle<Exception>()
.OrResult<ApiTaskResult<CheckResult>>(r => r.TaskState == TaskState.Running)
.WaitAndRetry(
50,
rc => TimeSpan.FromSeconds(5 * rc),
(driven, span) =>
{
Debug.WriteLine(driven.Exception is null
? $"Task {driven.Result.Id} is still running, waiting {span.TotalSeconds} seconds."
: $"{driven.Exception}, waiting {span.TotalSeconds} seconds.");
});
private readonly RetryPolicy<ApiTaskResult<PrepareResult>> _taskCheckDraftsPrepareResultQueryingRetryPolicy = Policy
.Handle<Exception>()
.OrResult<ApiTaskResult<PrepareResult>>(r => r.TaskState == TaskState.Running)
.WaitAndRetry(
50,
rc => TimeSpan.FromSeconds(5 * rc),
(driven, span) =>
{
Debug.WriteLine(driven.Exception is null
? $"Task {driven.Result.Id} is still running, waiting {span.TotalSeconds} seconds."
: $"{driven.Exception}, waiting {span.TotalSeconds} seconds.");
});
private readonly RetryPolicy<ApiTaskResult<Docflow>> _taskCheckDraftsSendDraftResultQueryingRetryPolicy = Policy
.Handle<Exception>()
.OrResult<ApiTaskResult<Docflow>>(r => r.TaskState == TaskState.Running)
.WaitAndRetry(
50,
rc => TimeSpan.FromSeconds(5 * rc),
(driven, span) =>
{
Debug.WriteLine(driven.Exception is null
? $"Task {driven.Result.Id} is still running, waiting {span.TotalSeconds} seconds."
: $"{driven.Exception}, waiting {span.TotalSeconds} seconds.");
});
From definitions you can see that i am using OrResult<T>
with predicate r => r.TaskState == TaskState.Running
.
Here is definition of ApiTaskResult:
public class ApiTaskResult<TTaskResultClass>
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("task-state")]
public TaskState TaskState { get; set; }
[JsonProperty("task-type")]
public string TaskType { get; set; }
[JsonProperty("task-result")]
public TTaskResultClass TaskResult { get; set; }
[JsonProperty("error")]
public ExternApiError Error { get; set; }
[JsonProperty("progress")]
public string Progress { get; set; }
}
TaskResult
is deserialized into concrete class that i usually pass as generic parameter and json deserializer create concrete class based on TaskType
.
I tried adding constraint for TTaskResultClass
that it should be an interface of ITaskResult
from which DraftsBuilderBuildResult
, CheckResult
, PrepareResult
and Docflow
derived and creating policy with interface as generic parameter, so i can reuse the same logic and i considered this because i am already seeing 4 places with the same code, knowing that it will probably increase in future.
private readonly RetryPolicy<ApiTaskResult<ITaskResult>> _taskCheckDraftsResultQueryingRetryPolicy = Policy
.Handle<Exception>()
.OrResult<ApiTaskResult<ITaskResult>>(r => r.TaskState == TaskState.Running)
.WaitAndRetry(
50,
rc => TimeSpan.FromSeconds(5 * rc),
(driven, span) =>
{
Debug.WriteLine(driven.Exception is null
? $"Task {driven.Result.Id} is still running, waiting {span.TotalSeconds} seconds."
: $"{driven.Exception}, waiting {span.TotalSeconds} seconds.");
});
I am using it in code like this:
apiSendDraftTaskResult = _taskCheckDraftsSendDraftResultQueryingRetryPolicy.Execute(() => draftsService.GetDraftsTaskResult<Docflow>(getDraftsSendTaskResultUrlSegments));
however if i try to use _taskCheckDraftsResultQueryingRetryPolicy
with interface and pass concrete class as generic parameter i get compilation error:
Severity Code Description Project File Line Suppression State
Error CS1662 Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type Omega.KonturExtern.Tests D:\TFS\1C\Omega.KonturExtern\Omega.KonturExtern.Tests\Chains\ChainsTests.cs 917 Active
Error CS0029 Cannot implicitly convert type 'Omega.KonturExtern.Models.DraftsBuilder.ApiTaskResult<Omega.KonturExtern.Models.Docflow>' to 'Omega.KonturExtern.Models.DraftsBuilder.ApiTaskResult<Omega.KonturExtern.Models.ITaskResult>' Omega.KonturExtern.Tests D:\TFS\1C\Omega.KonturExtern\Omega.KonturExtern.Tests\Chains\ChainsTests.cs 917 Active
Is there a way to overcome this problem or should i consider making some kind of factory ?