我想在NEST错误在HttpCodeResponse范围内时重试,并且我有以下通用策略:
public Policy<D> CreatePolicy<T, D>(
PolicyType policyType)
where T : Exception where D : IApiCallDetails
{
switch (policyType)
{
case PolicyType.WaitAndRetryAsync:
var httpStatusCodesWorthRetrying = new List<string>(this.policyConfiguration.HttpStatusCodesToRetrying.Split(','));
return Policy.Handle<T>()
.OrResult<D>(r => httpStatusCodesWorthRetrying.Select(int.Parse).ToList().Contains(r.HttpStatusCode.Value))
.WaitAndRetryAsync(
this.policyConfiguration.NumberOfRequestRetries,
retryAttempt => TimeSpan.FromSeconds(this.policyConfiguration.TimeInSecondsBetweenRetries),
onRetry: (exception, retryCount, context) =>
{
Log.Error($"[{context.PolicyKey}] Retry {retryCount} due to {exception.Exception.Message}.");
throw exception.Exception;
})
.WithPolicyKey(nameof(PolicyType.WaitAndRetryAsync));
default:
throw new ArgumentOutOfRangeException(nameof(policyType), policyType, null);
}
但是当我尝试应用elasticClient调用时,收到错误:
cannot implicity convert System.Threading.Tasks.Task<Nest.ISearchResponse<Model.Product>> to System.Threading.Tasks.Task<Elasticsearch.Net.IApiCallDetails>
Policy<IApiCallDetails> policyWaintAndRetry = this.policyFactory.CreatePolicy<ElasticsearchClientException, IApiCallDetails>(PolicyType.WaitAndRetryAsync);
var searchResponse = await policyWaintAndRetry.ExecuteAsync
action: () =>
this.client.SearchAsync<Product>(s => s
.From((request.PageNumber - 1) * request.PageSize)
.Size(request.PageSize)
.Index(GetIndexName(request.TenantId))
.Query(q => tq), CancellationToken.None),
contextData: new Polly.Context("SearchProductSearchAsync"))
.ConfigureAwait(false);
答案 0 :(得分:1)
对于NEST 5.x,我认为D
应具有IResponse
的通用参数约束; NEST中的每个响应都实现IResponse
,而来自IBodyWithApiCallDetails
的{{3}} 继承包含IApiCallDetails
和ApiCall
property。
答案 1 :(得分:1)
没有必要为处理异常和结果定义两个单独的策略。 this answer中的两个单独政策可以合并为:
public Policy<TResult> CreatePolicyForResultAndException<TResult, TException>(PolicyType policyType)
where TResult : HttpResponseMessage
where TException: Exception
{
switch (policyType)
{
case PolicyType.WaitAndRetryAsync:
var httpStatusCodesWorthRetrying = new List<string>(this.policyConfiguration.HttpStatusCodesToRetrying.Split(','));
return Policy.HandleResult<TResult>(r => httpStatusCodesWorthRetrying.Select(int.Parse).ToList().Contains((int)r.StatusCode))
.Or<TException>()
.WaitAndRetryAsync(
this.policyConfiguration.NumberOfRequestRetries,
retryAttempt => TimeSpan.FromSeconds(this.policyConfiguration.TimeInSecondsBetweenRetries),
onRetry: (outcome, retryCount, context) =>
{
Log.Error($"[{context.PolicyKey}] Retry {retryCount} due to {outcome.Result ?? outcome.Exception.Message}.");
if (outcome.Exception != null) throw outcome.Exception; // [*] if desired - see note after code sample
})
.WithPolicyKey(nameof(PolicyType.WaitAndRetryAsync));
default:
throw new ArgumentOutOfRangeException(nameof(policyType), policyType, null);
}
}
[*]上面代码示例中的这一行保留了original answer中onRetry
内的异常抛出。但是,在onRetry
内重新抛出异常是不常见的,因为策略不会处理在那里重新抛出的异常;在onRetry
内投掷将导致政策退出而不进行进一步的尝试。
答案 2 :(得分:0)
实际上我的问题是我试图创建一个处理异常和结果的策略,而实际上我应该为每个创建一个,然后将它们与policyWrap合并
第一个政策(结果):
public Policy<T> CreatePolicyForResult<T>(
PolicyType policyType)
where T : HttpResponseMessage
{
switch (policyType)
{
case PolicyType.WaitAndRetryAsync:
var httpStatusCodesWorthRetrying = new List<string>(this.policyConfiguration.HttpStatusCodesToRetrying.Split(','));
return Policy.HandleResult<T>(r => httpStatusCodesWorthRetrying.Select(int.Parse).ToList().Contains((int)r.StatusCode))
.WaitAndRetryAsync(
this.policyConfiguration.NumberOfRequestRetries,
retryAttempt => TimeSpan.FromSeconds(this.policyConfiguration.TimeInSecondsBetweenRetries))
.WithPolicyKey(nameof(PolicyType.WaitAndRetryAsync));
default:
throw new ArgumentOutOfRangeException(nameof(policyType), policyType, null);
}
}
第二个政策(例外):
public Policy CreatePolicyForException<T>(
PolicyType policyType)
where T : Exception
{
switch (policyType)
{
case PolicyType.WaitAndRetryAsync:
return Policy.Handle<T>()
.WaitAndRetryAsync(
this.policyConfiguration.NumberOfRequestRetries,
retryAttempt => TimeSpan.FromSeconds(this.policyConfiguration.TimeInSecondsBetweenRetries),
onRetry: (exception, retryCount, context) =>
{
Log.Error($"[{context.PolicyKey}] Retry {retryCount} due to {exception.Message}.");
throw exception;
})
.WithPolicyKey(nameof(PolicyType.WaitAndRetryAsync));
default:
throw new ArgumentOutOfRangeException(nameof(policyType), policyType, null);
}
}
用法:
var policyWaintAndRetryForExeption = this.policyFactory.CreatePolicyForException<ElasticsearchClientException>(PolicyType.WaitAndRetryAsync);
var policyWaintAndRetryForResult = this.policyFactory.CreatePolicyForResult<HttpResponseMessage>(PolicyType.WaitAndRetryAsync);
PolicyWrap<HttpResponseMessage> policyWrap = policyWaintAndRetryForExeption.WrapAsync(policyWaintAndRetryForResult);