/// <summary> /// 将满足中断条件的响应放入缓存 /// </summary> /// <param name="argument"></param> /// <param name="result">响应结果</param> public void SetFunseResult(RetryPolicyArgument argument, ResponseWrapperResult result) { //未开启中断配置,或成功响应跳过 if (argument.Option == null || !argument.Option.FuseEnabled || argument.IsSuccessResponse(result.Response)) { return; } var key = $"{argument.Service}.{argument.Module}"; FuseEntry entry = default; if (_cache.TryGetValue <FuseEntry>(key, out entry)) { if (entry.FailedCount >= argument.Option.FuseEnabledWhenFailedCount) { _logger.LogWarning($"服务{key}连续失败次数:{entry.FailedCount}已达阈值:{argument.Option.FuseEnabledWhenFailedCount},触发中断,时间:{argument.Option.FuseDuration}ms"); entry.Result = result; entry.Result.Fused = true; } } else { entry = new FuseEntry(); } entry.FailedCount++; _cache.Set <FuseEntry>(key, entry, TimeSpan.FromMilliseconds(argument.Option.FuseDuration)); }
/// <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); }
/// <summary> /// /// </summary> /// <param name="descriptor"></param> /// <param name="token"></param> /// <returns></returns> public async Task <ResponseWrapper> SendAndWrapAsync(RequestDescriptor descriptor, CancellationToken token = default) { var requestBuilder = _builderFactory.GetBuilder(descriptor.HttpOption.RequestBuilderType); var request = requestBuilder.GetRequest(descriptor); var result = _cacheOperator.Read(request); if (!result.HasHitCache) { var argument = new RetryPolicyArgument { Service = descriptor.ServiceName, Module = descriptor.ModuleName, Option = descriptor.HttpOption.RetryOption, Request = request, IsSuccessResponse = descriptor.HttpOption.IsSuccessResponse, Sending = async message => { var client = _clientFactory.CreateClient(descriptor.ServiceName); var responseMessage = await client.SendAsync(message, token); return(new HttpResponse(responseMessage)); } }; result = await _retryProcessor.ProcessAsync(argument); //调用日志记录器,写缓存(如果符合条件) _cacheOperator.Write(result.Response, descriptor.HttpOption.CacheOption); } try { //保存请求信息,请求结果 await _recordStore.WriteAsync(descriptor, result); } catch (Exception ex) { _logger.LogError(ex, $"日志记录器{_recordStore.GetType().Name},写入日志时出错:{ex.Message}"); } if (result.Exception != null) { throw result.Exception; } return(result); }