コード例 #1
0
        /// <summary>
        /// 检查是否满足重试条件
        /// </summary>
        /// <param name="option"></param>
        /// <param name="record"></param>
        /// <param name="retryCount"></param>
        /// <returns></returns>
        private bool CanRetry(RetryOption option, RequestRecord record, int retryCount)
        {
            if (option == null ||
                option.RetryCount <= 0 ||
                retryCount >= option.RetryCount)
            {
                return(false);
            }

            if (option.CanRetry != null)
            {
                return(option.CanRetry(record));
            }

            if ((option.TransientErrorRetry ?? false) && record.Exception != null)
            {
                if (record.Exception is TimeoutException ||
                    record.Exception is OperationCanceledException ||
                    record.Exception is HttpRequestException)
                {
                    return(true);
                }
                return(false);
            }

            var statusCode = (int)record.Response.StatusCode;
            var method     = record.Response.RequestMessage.Method.ToString();

            if (option.RetryStatusCodes?.Contains(statusCode) ?? false &&
                (option.RetryMethods?.Contains(method, StringComparer.CurrentCultureIgnoreCase) ?? false))
            {
                return(true);
            }
            return(false);
        }
コード例 #2
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="argument"></param>
        /// <returns></returns>
        public async Task <ResponseWrapperResult> ProcessAsync(RetryPolicyArgument argument)
        {
            var fusedResult = TryGetFuseResult(argument.Service, argument.Module);

            if (fusedResult != null)
            {
                return(fusedResult);
            }

            var records = new List <RequestRecord>();
            var option  = argument.Option;

            await HandleException(argument.Request, async() =>
            {
                var timeoutToken = (option?.TotalTimeout ?? 0) > 0
                     ? new CancellationTokenSource(TimeSpan.FromMilliseconds(option.TotalTimeout))
                     : new CancellationTokenSource();
                return(await SendWithRetryAsync(option, argument.Request, argument.Sending, records, timeoutToken.Token));
            }, record =>
            {
                //只有执行超时才会抛ExecutionHttpException,意味着重试结束
                if (record.Exception is ExecutionHttpException executionEx)
                {
                    record.Request   = executionEx.Request;
                    record.Exception = executionEx.InnerException;
                    record.Duration  = GetDuration(record.Request.TimeStamp);
                    records.Add(record);
                }
                return(record);
            });

            var result = new ResponseWrapperResult
            {
                Request    = argument.Request,
                Records    = records,
                Duration   = GetDuration(argument.Request.TimeStamp),
                RetryCount = records.Count() > 1 ? records.Count() - 1 : 0
            };
            //获取有效请求记录
            RequestRecord vaildRecord = result.Records.LastOrDefault(x => x.Response != null)
                                        ?? result.Records.LastOrDefault();

            result.Response  = vaildRecord?.Response;
            result.Exception = vaildRecord?.Exception;
            _logger.LogInformation($"请求{argument.Request.RequestUri}执行完毕,用时:{result.Duration}ms");
            SetFunseResult(argument, result);
            return(result);
        }
コード例 #3
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="request"></param>
        /// <param name="running"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        private async Task <RequestRecord> HandleException(HttpRequest request, Func <Task <RequestRecord> > running, Func <RequestRecord, RequestRecord> callback)
        {
            RequestRecord record = default;

            try
            {
                record = await running();
            }
            catch (Exception ex)
            {
                record = new RequestRecord
                {
                    Request   = request,
                    Exception = ex,
                    Duration  = GetDuration(request.TimeStamp)
                };
            }
            return(callback(record));
        }
コード例 #4
0
        /// <summary>
        /// 重试逻辑
        /// </summary>
        /// <param name="option"></param>
        /// <param name="request"></param>
        /// <param name="sending"></param>
        /// <param name="records"></param>
        /// <param name="timeoutToken"></param>
        /// <param name="retryCount"></param>
        /// <returns></returns>
        private async Task <RequestRecord> SendWithRetryAsync(RetryOption option, HttpRequest request,
                                                              Func <HttpRequest, Task <HttpResponse> > sending,
                                                              List <RequestRecord> records, CancellationToken timeoutToken, int retryCount = 0)
        {
            if (timeoutToken.IsCancellationRequested)
            {
                throw new ExecutionHttpException(request, new TimeoutException($"请求超时,在{option.TotalTimeout}ms内未获取到结果"));
            }
            records = records ?? new List <RequestRecord>();
            var record = await HandleException(request, async() =>
            {
                var response      = await sending(request);
                var requestRecord = new RequestRecord
                {
                    Request  = request,
                    Response = response,
                    Duration = response.Duration
                };
                return(requestRecord);
            }, requestRecord =>
            {
                records.Add(requestRecord);
                return(requestRecord);
            });

            if (!CanRetry(option, record, retryCount))
            {
                return(record);
            }
            //重试间隔时间
            var waitTime = option.WaitIntervals[retryCount];

            //等待重试间隔时间
            await Waiting(request, waitTime, option.TotalTimeout, timeoutToken);

            request = request.Clone();
            //开始重试
            return(await SendWithRetryAsync(option, request, sending, records, timeoutToken, ++retryCount));
        }