コード例 #1
0
        protected override Task <HttpResponseMessage> SendAsync(HttpRequestMessage httpRequestMessage, CancellationToken cancellationToken)
        {
            var jitterer = new Random();

            var retryPolicyWithJitter = HttpPolicyExtensions.
                                        HandleTransientHttpError().
                                        WaitAndRetryAsync(
                retryCount: RETRY_ATTEMPTS_ON_TRANSIENT_ERROR,
                sleepDurationProvider: retryNumber => TimeSpan.FromSeconds(Math.Pow(2, retryNumber)) + TimeSpan.FromMilliseconds(jitterer.Next(0, 100))
                );

            var bulkheadPolicy = Policy.BulkheadAsync <HttpResponseMessage>(maxParallelization: 3, maxQueuingActions: 25);

            var circuitBreakerPolicy =
                Policy.HandleResult <HttpResponseMessage>(rm => !rm.IsSuccessStatusCode).
                AdvancedCircuitBreakerAsync(
                    failureThreshold: 0.25,                                     // If 25% or more of requests fail
                    samplingDuration: TimeSpan.FromSeconds(60),                 // in a 60 second period
                    minimumThroughput: 7,                                       // and there have been at least 7 requests in that time
                    durationOfBreak: TimeSpan.FromSeconds(30)                   // then open the circuit for 30 seconds
                    );

            var policy = HttpMethod.Get == httpRequestMessage.Method
                ? Policy.WrapAsync(retryPolicyWithJitter, bulkheadPolicy, circuitBreakerPolicy)
                : Policy.WrapAsync(bulkheadPolicy, circuitBreakerPolicy);

            return(policy.ExecuteAsync(() => base.SendAsync(httpRequestMessage, cancellationToken)));
        }
コード例 #2
0
        /// <summary>
        /// 生成默认的Polly策略
        /// </summary>
        /// <returns></returns>
        protected virtual List <IAsyncPolicy <HttpResponseMessage> > GenerateDefaultRefitPolicies()
        {
            //重试策略
            var retryPolicy = Policy.Handle <ApiException>()
                              .OrResult <HttpResponseMessage>(response => response.StatusCode == System.Net.HttpStatusCode.BadGateway)
                              .WaitAndRetryAsync(new[]
            {
                TimeSpan.FromSeconds(1),
                TimeSpan.FromSeconds(5),
                TimeSpan.FromSeconds(10)
            });
            //超时策略
            var timeoutPolicy = Policy.TimeoutAsync <HttpResponseMessage>(10);
            //隔离策略
            var bulkheadPolicy = Policy.BulkheadAsync <HttpResponseMessage>(10, 100);
            //回退策略
            //断路策略
            var circuitBreakerPolicy = Policy.Handle <ApiException>()
                                       .CircuitBreakerAsync(2, TimeSpan.FromMinutes(1));

            return(new List <IAsyncPolicy <HttpResponseMessage> >()
            {
                //timeoutPolicy
            });
        }
コード例 #3
0
        static SoChainNetworkInfoProvider()
        {
            HttpClient = new HttpClient
            {
                BaseAddress           = new Uri("https://chain.so/api/v2"),
                DefaultRequestHeaders =
                {
                    Accept = { new MediaTypeWithQualityHeaderValue("application/json") }
                },
                Timeout = TimeSpan.FromSeconds(15)
            };

            var policyBuilder = Policy.HandleResult <HttpResponseMessage>(h => !h.IsSuccessStatusCode)
                                .Or <Exception>();

            SoChainPolicy = Policy.WrapAsync(
                policyBuilder.FallbackAsync(new HttpResponseMessage(HttpStatusCode.BadRequest))
                , policyBuilder.WaitAndRetryForeverAsync(_ => TimeSpan.FromSeconds(1))
                // throttle
                , Policy.HandleResult <HttpResponseMessage>(_ => true)
                .Or <Exception>()
                .CircuitBreakerAsync(1, TimeSpan.FromSeconds(5))
                , Policy.BulkheadAsync <HttpResponseMessage>(1)
                , Policy.TimeoutAsync <HttpResponseMessage>(_ => TimeSpan.FromSeconds(5))
                );
        }
コード例 #4
0
        public void AddAllRpcService()
        {
            //重试策略
            var retryPolicy = Policy.Handle <HttpRequestException>()
                              .OrResult <HttpResponseMessage>(response => response.StatusCode == System.Net.HttpStatusCode.BadGateway)
                              .WaitAndRetryAsync(new[]
            {
                TimeSpan.FromSeconds(1),
                TimeSpan.FromSeconds(5),
                TimeSpan.FromSeconds(10)
            });
            //超时策略
            var timeoutPolicy = Policy.TimeoutAsync <HttpResponseMessage>(30);
            //隔离策略
            var bulkheadPolicy = Policy.BulkheadAsync <HttpResponseMessage>(10, 100);
            //回退策略
            //断路策略
            var circuitBreakerPolicy = Policy.Handle <Exception>()
                                       .CircuitBreakerAsync(2, TimeSpan.FromMinutes(1));

            var policies = new List <IAsyncPolicy <HttpResponseMessage> >()
            {
                timeoutPolicy
            };

            //注册用户认证、鉴权服务Rpc服务到容器
            var authServerAddress = (_env.IsProduction() || _env.IsStaging()) ? "adnc.usr.webapi" : "http://localhost:5010";

            base.AddRpcService <IAuthRpcService>(authServerAddress, policies);
        }
コード例 #5
0
        /// <summary>
        /// Generates a Polly <see cref="BulkheadPolicy{HttpResponseMessage}"/> from the configuration.
        /// </summary>
        /// <param name="logger">The <see cref="ILogger"/> instance to use for logging.</param>
        /// <returns>A <see cref="BulkheadPolicy{HttpResponseMessage}"/> instance.</returns>
        public IAsyncPolicy <HttpResponseMessage> AsTypeModel(ILogger logger)
        {
            _ = logger ?? throw new ArgumentNullException(nameof(logger));

            if (MaxParallelization < 1)
            {
                logger.LogCritical("{PolicyConfig} : {Property} must be greater than 0", nameof(BulkheadConfig), "bandwidth");
                throw new InvalidOperationException("bandwidth must be greater than 0");
            }

            if (MaxQueuingActions.HasValue && MaxQueuingActions.Value < 1)
            {
                logger.LogCritical("{PolicyConfig} : {Property} must be greater than 0", nameof(BulkheadConfig), "queueLength");
                throw new InvalidOperationException("queueLength must be greater than 0");
            }

            // Create delegates
            Task OnBulkheadRejectedAsync(Context context)
            {
                logger.LogInformation("{PolicyKey} at {OperationKey}: Request rejected by bulkhead",
                                      context.PolicyKey, context.OperationKey);
                return(Task.CompletedTask);
            }

            // Generate policy
            var policy = MaxQueuingActions.HasValue ?
                         Policy.BulkheadAsync <HttpResponseMessage>(
                MaxParallelization, MaxQueuingActions.Value, OnBulkheadRejectedAsync)
                : Policy.BulkheadAsync <HttpResponseMessage>(
                MaxParallelization, OnBulkheadRejectedAsync);

            return(policy);
        }
コード例 #6
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            var proxy = Configuration.GetValue <string>("Proxy");

            if (string.IsNullOrEmpty(proxy))
            {
                _logger.LogWarning("Невозможно получить URL прокси. Ананимный парсинг невозможен.");
            }

            services.AddControllers().AddNewtonsoftJson();

            // services.AddHostedService<SchedulerService>();
            services.AddHostedService <MyWorker>();
            services.AddSingleton <IMyQueue, MyQueue>();

            services.AddHttpClient <ICheckPackagesService, CheckPackagesService>(x => { })
            .ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler
            {
                AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,
                Proxy = new WebProxy()
            })
            .AddPolicyHandler(PolicySettings.GetRetryPolicy())
            .AddPolicyHandler(PolicySettings.GetTimeoutPolicy());

            Policy.BulkheadAsync(10);

            services.AddHttpClient <ISendCallbackService, SendCallbackService>(x =>
            {
                x.Timeout = TimeSpan.FromSeconds(90);
            });

            services.AddTransient <IRevisionJob, RevisionJob>();
        }
コード例 #7
0
        private async Task <HttpResponseMessage> trySendAsync(HttpRequestMessage request)
        {
            #region 超时
            var policyTimeout = Policy.TimeoutAsync(Options.SpiderHttpRequestOptions.Timeout, TimeoutStrategy.Pessimistic,
                                                    async(context, timespan, task) =>
            {
                _logger.LogWarning($"请求url:{request.RequestUri}超时{timespan.TotalMilliseconds}ms,\r\n body: {request.Content.ToStr()} ");
            }).AsAsyncPolicy <HttpResponseMessage>();
            #endregion

            #region 错误异常 重试
            var policyException = Policy.Handle <HttpRequestException>()
                                  .RetryAsync(Options.SpiderHttpRequestOptions.RetryCount, async(exception, retryCount, context) =>
            {
                _logger.LogWarning(exception, $"请求url:{request.RequestUri}出错,重试次数:{retryCount}次,\r\n body: {request.Content.ToStr()} ");
                //重试 重新去获取新的baseurl
                setHttpClientBaseAddress(ServiceName);
            }).AsAsyncPolicy <HttpResponseMessage>();
            #endregion

            #region 超过最大请求并发数
            var policyBulkhead = Policy.BulkheadAsync(Options.SpiderHttpRequestOptions.MaxParallelization, async(context) =>
            {
                _logger.LogWarning($"请求url:{request.RequestUri}超过请求{Options.SpiderHttpRequestOptions.MaxParallelization}并发数,\r\n body: {request.Content.ToStr()} ");

                // do something
            }).AsAsyncPolicy <HttpResponseMessage>();
            #endregion

            #region 熔断
            //80%出错就熔断, 第二个参数  多长时间内出现80%错误,
            //第三个参数  当请求比较少时候,最少的请求数,
            //下面就是  10秒内 请求小于100个就还不需要熔断。第四个参数 熔断时间长度

            var policyAdvancedCircuitBreaker = Policy.Handle <HttpRequestException>().AdvancedCircuitBreakerAsync(
                failureThreshold: Options.SpiderHttpRequestOptions.FailureThreshold,
                samplingDuration: Options.SpiderHttpRequestOptions.SamplingDuration,
                minimumThroughput: Options.SpiderHttpRequestOptions.MinimumThroughput,
                durationOfBreak: Options.SpiderHttpRequestOptions.DurationOfBreak,
                onBreak: (r, t) => { },
                onReset: () => { },
                onHalfOpen: () => { }).AsAsyncPolicy <HttpResponseMessage>();
            #endregion

            #region 降级
            var policyFallback = Policy.Handle <HttpRequestException>()
                                 .FallbackAsync(async(exception, context, cancellationToken) =>
            {
            }, async(exception, context) =>
            {
            }).AsAsyncPolicy <HttpResponseMessage>();
            #endregion


            return(await Policy.WrapAsync <HttpResponseMessage>(policyTimeout, policyException, policyBulkhead, policyAdvancedCircuitBreaker).ExecuteAsync(async() =>
            {
                var response = await _httpClient.SendAsync(request);
                return response;
            }));
        }
コード例 #8
0
 public virtual PolicyWrapper <HttpResponseMessage> Build()
 {
     return(new PolicyWrapper <HttpResponseMessage>
     {
         Policy = Policy.BulkheadAsync <HttpResponseMessage>(MaxParallelization, QueueSize)
     });
 }
コード例 #9
0
        /// <summary>
        /// Bulkhead Policy Config
        /// </summary>
        /// <param name="maxParallelism">Maximum parallelization of executions through the bulkhead</param>
        /// <param name="maxQueuingActions">Maximum number of actions that may be queuing (waiting to acquire an execution slot) at any time</param>
        /// <returns></returns>
        public ArtesianPolicyConfig BulkheadPolicyConfig(int maxParallelism = MaxParallelismDefault, int maxQueuingActions = MaxQueuingActionsDefault)
        {
            _bulkheadPolicy = Policy
                              .BulkheadAsync(maxParallelism, maxQueuingActions);

            return(this);
        }
コード例 #10
0
        public void Should_call_onBulkheadRejected_with_passed_context()
        {
            string  operationKey           = "SomeKey";
            Context contextPassedToExecute = new Context(operationKey);

            Context contextPassedToOnRejected    = null;
            Func <Context, Task> onRejectedAsync = async ctx => { contextPassedToOnRejected = ctx; await TaskHelper.EmptyTask.ConfigureAwait(false); };

            using (var bulkhead = Policy.BulkheadAsync <int>(1, onRejectedAsync))
            {
                TaskCompletionSource <object> tcs = new TaskCompletionSource <object>();
                using (CancellationTokenSource cancellationSource = new CancellationTokenSource())
                {
                    Task.Run(() => {
                        bulkhead.ExecuteAsync(async() =>
                        {
                            await tcs.Task.ConfigureAwait(false);
                            return(0);
                        });
                    });

                    Within(CohesionTimeLimit, () => Expect(0, () => bulkhead.BulkheadAvailableCount, nameof(bulkhead.BulkheadAvailableCount)));

                    bulkhead.Awaiting(async b => await b.ExecuteAsync(ctx => Task.FromResult(1), contextPassedToExecute)).Should().Throw <BulkheadRejectedException>();

                    cancellationSource.Cancel();
                    tcs.SetCanceled();
                }

                contextPassedToOnRejected.Should().NotBeNull();
                contextPassedToOnRejected.OperationKey.Should().Be(operationKey);
                contextPassedToOnRejected.Should().BeSameAs(contextPassedToExecute);
            }
        }
コード例 #11
0
        public void Should_call_onBulkheadRejected_with_passed_context()
        {
            string  operationKey           = "SomeKey";
            Context contextPassedToExecute = new Context(operationKey);

            Context contextPassedToOnRejected    = null;
            Func <Context, Task> onRejectedAsync = async ctx => { contextPassedToOnRejected = ctx; await TaskHelper.EmptyTask.ConfigureAwait(false); };

            var bulkhead = Policy.BulkheadAsync(1, onRejectedAsync);

            TaskCompletionSource <object> tcs = new TaskCompletionSource <object>();

            using (CancellationTokenSource cancellationSource = new CancellationTokenSource())
            {
                Task.Run(() => {
                    bulkhead.ExecuteAsync(async() =>
                    {
                        await tcs.Task.ConfigureAwait(false);
                    });
                });

                Within(shimTimeSpan, () => bulkhead.BulkheadAvailableCount.Should().Be(0)); // Time for the other thread to kick up and take the bulkhead.

                bulkhead.Awaiting(async b => await b.ExecuteAsync(ctx => TaskHelper.EmptyTask, contextPassedToExecute)).ShouldThrow <BulkheadRejectedException>();

                cancellationSource.Cancel();
                tcs.SetCanceled();
            }

            contextPassedToOnRejected.Should().NotBeNull();
            contextPassedToOnRejected.OperationKey.Should().Be(operationKey);
            contextPassedToOnRejected.Should().BeSameAs(contextPassedToExecute);
        }
コード例 #12
0
        /// <summary>
        /// Configures Polly Policy Handlers using options defined in <typeparamref name="T"/>.
        /// Adds retry, circuit breaker and bulkhead policies depending on the configured <see cref="HttpOptions"/> values.
        /// </summary>
        /// <typeparam name="T">The option type.</typeparam>
        /// <param name="builder">The <see cref="IHttpClientBuilder"/>.</param>
        /// <returns>The updated <see cref="IHttpClientBuilder"/>.</returns>
        public static IHttpClientBuilder AddPoliciesFromOptions <T>(this IHttpClientBuilder builder)
            where T : HttpOptions, new()
        {
            if (builder == null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            var options = builder.Services.BuildServiceProvider().GetRequiredService <IOptions <T> >().Value;

            if (options.ErrorsAllowedBeforeBreaking > 0)
            {
                builder = builder.AddTransientHttpErrorPolicy(p => p.CircuitBreakerAsync(options.ErrorsAllowedBeforeBreaking, options.BreakDuration));
            }

            if (options.NumberOfRetries > 0)
            {
                if (options.RetriesMaximumSleepDuration == TimeSpan.FromTicks(0))
                {
                    builder = builder.AddTransientHttpErrorPolicy(p => p.WaitAndRetryAsync(options.NumberOfRetries, _ => options.RetriesSleepDuration));
                }
                else
                {
                    builder = builder.AddTransientHttpErrorPolicy(
                        p => p.WaitAndRetryAsync(DecorrelatedJitter(options.NumberOfRetries, options.RetriesSleepDuration, options.RetriesMaximumSleepDuration)));
                }
            }

            if (options.MaxParallelization > 0)
            {
                builder = builder.AddPolicyHandler(Policy.BulkheadAsync(options.MaxParallelization).AsAsyncPolicy <HttpResponseMessage>());
            }

            return(builder);
        }
コード例 #13
0
        /// <summary>
        /// Constructor.
        /// </summary>
        public ForgeOSS(IHttpClientFactory clientFactory, IOptions <ForgeConfiguration> optionsAccessor, ILogger <ForgeOSS> logger)
        {
            _clientFactory = clientFactory;
            _logger        = logger;
            Configuration  = optionsAccessor.Value.Validate();

            string apiBaseUrl = Configuration.AuthenticationAddress.GetLeftPart(System.UriPartial.Authority);

            Autodesk.Forge.Client.Configuration.Default.setApiClientUsingDefault(new ApiClient(apiBaseUrl));

            RefreshApiToken();

            // create policy to refresh API token on expiration (401 error code)
            var refreshTokenPolicy = Policy
                                     .Handle <ApiException>(e => e.ErrorCode == StatusCodes.Status401Unauthorized)
                                     .RetryAsync(5, (_, __) => RefreshApiToken());

            var bulkHeadPolicy       = Policy.BulkheadAsync(10, int.MaxValue);
            var rateLimitRetryPolicy = Policy
                                       .Handle <ApiException>(e => e.ErrorCode == StatusCodes.Status429TooManyRequests)
                                       .WaitAndRetryAsync(new[] {
                TimeSpan.FromSeconds(10),
                TimeSpan.FromSeconds(20),
                TimeSpan.FromSeconds(40)
            });

            _ossResiliencyPolicy = refreshTokenPolicy.WrapAsync(rateLimitRetryPolicy).WrapAsync(bulkHeadPolicy);
        }
コード例 #14
0
ファイル: Startup.cs プロジェクト: andrekiba/WPC19
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();

            #region Bulkhead

            AsyncBulkheadPolicy <ApiResponse <Project> > bulkheadPolicy = Policy
                                                                          .BulkheadAsync <ApiResponse <Project> >(2, 4, onBulkheadRejectedAsync: context =>
            {
                Debug.WriteLine("Bulkhead reject execution");
                return(Task.CompletedTask);
            });

            #endregion

            services.AddRefitClient <IAzureDevOpsApi>()
            .ConfigureHttpClient((serviceProvider, client) =>
            {
                client.BaseAddress = new Uri(Configuration["AppSettings:AzureDevOpsApiAddress"]);
                client.DefaultRequestHeaders.Add("Accept", "application/json");
            });
            //.AddPolicyHandler(bulkheadPolicy);

            services.AddSingleton(bulkheadPolicy);
        }
コード例 #15
0
        private async Task <Result <bool> > PostChargeOnCustomerCard(ICollection <ScheduledPayment>
                                                                     scheduledPayments)
        {
            // A bulkhead isolation policy to restrict number of concurrent calls
            // https://markheath.net/post/constraining-concurrent-threads-csharp
            var bulkhead            = Policy.BulkheadAsync(20, Int32.MaxValue);
            var chargeCustomerTasks = new List <Task>();

            foreach (var scheduledPayment in scheduledPayments)
            {
                var t = bulkhead.ExecuteAsync(async() =>
                {
                    var postStripeChargeResult = await CreateCharge(scheduledPayment);

                    _logger.LogTrace(postStripeChargeResult.ToString());

                    // In the same loop Update the Payment
                    bool isPaymentPosted = IsPaymentPosted(postStripeChargeResult);

                    var updatePayment = await UpdatePayment(scheduledPayment.Id, isPaymentPosted);

                    if (!updatePayment)
                    {
                        PostFailureToQueue(scheduledPayment);
                    }
                });

                chargeCustomerTasks.Add(t);
            }

            await Task.WhenAll(chargeCustomerTasks);

            return(Result.Ok(true));
        }
コード例 #16
0
        public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
        .UseSystemd()
        .ConfigureServices((hostContext, services) =>
        {
            services.AddOptions();
            services.AddSingleton <LuupWrapper>();
            services.AddHostedService <MQTTServer>();

            // HTTP CLIENTS
            services.AddHttpClient(NamedHttpClients.LuupClient, client =>
            {
                //client.DefaultRequestVersion = new Version(2, 0); // HTTP 2
                client.Timeout = TimeSpan.FromMilliseconds(double.Parse(hostContext.Configuration["luup:timeout"] ?? "10000"));
                client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4204.0 Safari/537.36 Edg/86.0.587.0");
                client.DefaultRequestHeaders.Add("Upgrade-Insecure-Requests", "1");
            })
            .AddPolicyHandler(Policy.BulkheadAsync <HttpResponseMessage>(1, 500))
            .AddPolicyHandler(HttpPolicyExtensions
                              .HandleTransientHttpError()
                              .OrResult(msg => (int)msg.StatusCode >= 500)
                              .WaitAndRetryAsync(int.Parse(hostContext.Configuration["luup:retries"] ?? "5"), retryAttempt => TimeSpan.FromMilliseconds(Math.Pow(2, retryAttempt) * double.Parse(hostContext.Configuration["luup:retryAttemptTimeout"] ?? "500"))));
        })
        .ConfigureAppConfiguration((hostingContext, config) =>
        {
            var env = hostingContext.HostingEnvironment;

            var path = GetCurrentPath();

            config.SetBasePath(path)
            .AddJsonFile("appsettings.json", optional: true)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
            .AddEnvironmentVariables();
        })
        .UseSerilog((hostingContext, loggerConfiguration) =>
コード例 #17
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            #region Other ways of injecting policies
            //IAsyncPolicy<HttpResponseMessage> httpRetryPolicy =
            //   Policy.HandleResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode).RetryAsync(3);
            //services.AddHttpClient("RemoteServer", client =>
            //{
            //    client.BaseAddress = new Uri("http://aspnetmonsters.com");
            //    //client.DefaultRequestHeaders.Add("Accept", "application/json");
            //}).AddPolicyHandler(httpRetryPolicy);
            #endregion

            #region Advanced Circuit Breaker
            //CircuitBreakerPolicy<HttpResponseMessage> breakerPolicy = Policy
            //  .HandleResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
            //  .AdvancedCircuitBreakerAsync(0.5, TimeSpan.FromSeconds(60), 7, TimeSpan.FromSeconds(15),
            //      OnBreak, OnReset, OnHalfOpen);
            #endregion


            CircuitBreakerPolicy <HttpResponseMessage> breakerPolicy = Policy
                                                                       .HandleResult <HttpResponseMessage>(r => !r.IsSuccessStatusCode)
                                                                       .CircuitBreakerAsync(2, TimeSpan.FromSeconds(10), OnBreak, OnReset, OnHalfOpen);


            BulkheadPolicy <HttpResponseMessage> bulkheadIsolationPolicy = Policy
                                                                           .BulkheadAsync <HttpResponseMessage>(2, 4, onBulkheadRejectedAsync: OnBulkheadRejectedAsync);


            services.AddHttpClient("RemoteServer", client =>
            {
                client.BaseAddress = new Uri("http://aspnetmonsters.com");
                //client.DefaultRequestHeaders.Add("Accept", "application/json");
            });
            services.AddHttpClient("InventoryClient", client =>
            {
                client.BaseAddress = new Uri("http://localhost:57697/api/");
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Add("Accept", "application/json");
            }).
            ConfigurePrimaryHttpMessageHandler(handler => new HttpClientHandler
            {
                AutomaticDecompression = DecompressionMethods.GZip
            });

            IAsyncPolicy <HttpResponseMessage> httpRetryPolicy =
                Policy.HandleResult <HttpResponseMessage>(r => !r.IsSuccessStatusCode)
                .RetryAsync(3);

            services.AddSingleton <IAsyncPolicy <HttpResponseMessage> >(httpRetryPolicy);

            services.AddSingleton <CircuitBreakerPolicy <HttpResponseMessage> >(breakerPolicy);
            services.AddSingleton <BulkheadPolicy <HttpResponseMessage> >(bulkheadIsolationPolicy);
            services.AddSingleton(CustomPolicyWrap());

            services.AddSingleton <PolicyHolder>(new PolicyHolder());
            services.AddSingleton <IPolicyRegistry <string> >(GetRegistry());
            services.AddMvc();
        }
コード例 #18
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure <ApiSettings>(options => Configuration.GetSection(nameof(ApiSettings)).Bind(options));

            services.AddMemoryCache();

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

            // Register the Swagger generator, defining 1 or more Swagger documents
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo
                {
                    Version     = "v1",
                    Title       = "Top 20 best stories.",
                    Description = "Retrieve the top 20 best stories from Hacker News API",
                    Contact     = new OpenApiContact
                    {
                        Name  = "Jorge Vinagre",
                        Email = string.Empty,
                        Url   = new Uri("https://github.com/jorgevinagre"),
                    }
                });

                // Set the comments path for the Swagger JSON and UI.
                var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
                var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
                c.IncludeXmlComments(xmlPath);
            });


            // Limit the max concurrent requests
            // Extra resilience for high-throughput systems by preventing a faulting downstream system causing an excessive resource bulge of queuing calls upstream.
            int maxParallelism = int.Parse(Configuration.GetSection("ApiSettings:MaxParallelJobs").Value);
            int maxQueueSize   = int.Parse(Configuration.GetSection("ApiSettings:MaxQueueItems").Value);

            var throttler = Policy.BulkheadAsync <HttpResponseMessage>(maxParallelization: maxParallelism, maxQueuingActions: maxQueueSize);


            // Add Hacker News baseUri client services as a typed client for HttpClientFactory
            services
            // Add typed client and set its base url
            .AddHttpClient <IHackerNewsHttpClient, HackerNewsHttpClient>(client =>
            {
                // Set the base address to backoffice client
                var baseUri = Configuration.GetSection("HackerNews:uri").Value;

                if (!baseUri.EndsWith("/"))
                {
                    baseUri = string.Concat(baseUri, "/");
                }

                client.BaseAddress = new Uri(baseUri);
            }).AddPolicyHandler(throttler);

            services.AddScoped <IBestStoriesService, BestStoriesService>();

            services.AddSingleton <ICacheService, MemoryCacheService>();
        }
コード例 #19
0
        private AsyncBulkheadPolicy <HttpResponseMessage> BulkheadPolicy()
        {
            var bulkhead = Policy
                           .BulkheadAsync <HttpResponseMessage>(_options.Bulkhead.MaxParallelization,
                                                                _options.Bulkhead.MaxQueuingActions);

            return(bulkhead);
        }
コード例 #20
0
ファイル: PollyTraining.cs プロジェクト: lv-conner/AOP
 public PollyTraining()
 {
     _proxy = Policy.BulkheadAsync(2, 1, c =>
     {
         Console.WriteLine("reject request");
         return(Task.CompletedTask);
     });
 }
コード例 #21
0
        public void Should_throw_when_onBulkheadRejected_is_null()
        {
            Action policy = () => Policy
                            .BulkheadAsync(1, 0, null);

            policy.ShouldThrow <ArgumentNullException>().And
            .ParamName.Should().Be("onBulkheadRejectedAsync");
        }
コード例 #22
0
        public void Should_throw_when_maxQueuingActions_less_than_zero()
        {
            Action policy = () => Policy
                            .BulkheadAsync(1, -1);

            policy.ShouldThrow <ArgumentOutOfRangeException>().And
            .ParamName.Should().Be("maxQueuingActions");
        }
コード例 #23
0
        public void Should_throw_when_maxparallelization_less_or_equal_to_zero()
        {
            Action policy = () => Policy
                            .BulkheadAsync(0, 1);

            policy.ShouldThrow <ArgumentOutOfRangeException>().And
            .ParamName.Should().Be("maxParallelization");
        }
コード例 #24
0
        public static IEnumerable <Task> RunInBulkhead <T>(this IEnumerable <T> source, Func <T, Task> func, int maxParallelization)
        {
            var enumerable = source as T[] ?? source.ToArray();
            var policy     = Policy.BulkheadAsync(maxParallelization, enumerable.Count());
            var tasks      = enumerable.Select(item => policy.ExecuteAsync(() => func(item))).ToArray();

            return(tasks);
        }
コード例 #25
0
        /// <summary>
        /// Create a retry policy for Invoke execptions.
        /// </summary>
        private IAsyncPolicy CreateInvokePolicy()
        {
            var auth = CreateAuthenticationPolicy();
            var hash = CreateInvalidHashPolicy();
            var bulk = Policy.BulkheadAsync(_options.RequestMaxParallel, int.MaxValue);

            return(Policy.WrapAsync(auth, hash, bulk));
        }
コード例 #26
0
ファイル: Startup.cs プロジェクト: esatemre/HolidayOptimizer
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();

            services.AddSingleton <IPublicHolidayProvider, PublicHolidayProvider>();
            services.AddSingleton <ITimezoneProvider, TimezoneProvider>();
            services.AddSingleton <ISupportedCountries, SupportedCountries>();
            services.AddScoped <IHolidayOptimizeService, HolidayOptimizeService>();

            services.AddSwaggerGen(swagger => {
                swagger.SwaggerDoc("v1", new OpenApiInfo {
                    Title = "HolidayOptimizer.WebAPI", Version = "1.0.0", Description = "HolidayOptimizer Web API"
                });
                // Set the comments path for the Swagger JSON and UI.
                var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
                var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
                swagger.IncludeXmlComments(xmlPath);
            });

            //memory cache
            services.AddMemoryCache();

            //response caching
            services.AddResponseCaching();


            //throttle request with Polly
            int maxParallelism     = 10;
            int maxQueueingActions = 100;
            var throttler          = Policy.BulkheadAsync <System.Net.Http.HttpResponseMessage>(maxParallelism, maxQueueingActions);

            // Configure a client named as "Nager", with various default properties.
            services.AddHttpClient("PublicHolidayApi", client => {
                client.BaseAddress = new Uri("https://date.nager.at/api/v2/PublicHolidays/");
            })
            .AddPolicyHandler(throttler)
            .AddTransientHttpErrorPolicy(builder => builder.WaitAndRetryAsync(new[]
            {
                TimeSpan.FromSeconds(1),
                TimeSpan.FromSeconds(5),
                TimeSpan.FromSeconds(10)
            }));


            // Configure a client named as "TimezoneApi", with various default properties.
            services.AddHttpClient("TimezoneApi", client => {
                client.BaseAddress = new Uri("https://restcountries.eu/rest/v2/alpha/");
            })
            .AddPolicyHandler(throttler)
            .AddTransientHttpErrorPolicy(builder => builder.WaitAndRetryAsync(new[]
            {
                TimeSpan.FromSeconds(1),
                TimeSpan.FromSeconds(5),
                TimeSpan.FromSeconds(10)
            }));
        }
コード例 #27
0
        public WebcrawlerService(TimeSpan timeout)
        {
            this.client = new HttpClient();

            this.policy = Policy.WrapAsync(
                Policy.Handle <Exception>(e => !(e is BrokenCircuitException))
                .RetryAsync(1),
                Policy.BulkheadAsync(5, 10),
                Policy.TimeoutAsync(timeout.Seconds)
                );
        }
コード例 #28
0
        private async static Task Download(Sftp client, IConfigurationRoot config)
        {
            var remotePath = config["RemotePath"];
            var localPath  = config["LocalPath"];
            var fileType   = config["FileType"];
            var stopWatch  = new Stopwatch();

            stopWatch.Start();
            Console.WriteLine("Fetching directory names...");
            var directoryNames = client.GetList($"{remotePath}/").Cast <SftpItem>().Where(item => item.IsDirectory).Select(item => item.Name);

            var  bulkhead     = Policy.BulkheadAsync(100, int.MaxValue);
            var  tasks        = new List <Task>();
            long downloadSize = 0;

            foreach (var name in directoryNames)
            {
                var remoteDirPath = Url.Combine(remotePath, name).ToString();
                var localDirPath  = Path.Combine(localPath, name).ToString();

                Console.WriteLine($"Fetching file names for {remoteDirPath}");
                var pattern  = new FileSet(remoteDirPath, $"*.{fileType}", TraversalMode.MatchFilesShallow);
                var fileInfo = await client.GetItemsAsync(pattern);

                foreach (var info in fileInfo)
                {
                    if (!info.IsDirectory)
                    {
                        var fullFileName   = info.Name;
                        var remoteFilePath = Url.Decode(Url.Combine(remoteDirPath, fullFileName), false).ToString();
                        var localFilePath  = Path.Combine(localDirPath, fullFileName).ToString();

                        var task = bulkhead.ExecuteAsync(async() =>
                        {
                            var bytesDownloaded = await client.GetFileAsync(remoteFilePath, localFilePath);
                            downloadSize       += bytesDownloaded;
                            Console.WriteLine($"Download from {remoteFilePath} to ${localFilePath}, size: {bytesDownloaded}");
                        });
                        tasks.Add(task);
                    }
                }
            }

            await Task.WhenAll(tasks);

            stopWatch.Stop();
            var elapsedTime = stopWatch.Elapsed;

            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine($"Download Time {elapsedTime.Hours}h:{elapsedTime.Minutes}m:{elapsedTime.Seconds}s:{elapsedTime.Milliseconds}ms");
            Console.WriteLine($"Download Size: {downloadSize}");
            Console.ResetColor();
            Console.Read();
        }
コード例 #29
0
        private IAsyncPolicy BuildPolicy(ICircuitRequest request, PolicySettings settings)
        {
            settings = settings ?? new PolicySettings();

            var maxParallelization = settings.MaxParallelization ?? 100;
            var maxQueingActions   = settings.MaxQueingActions ?? 10;

            var timeout = AppliedTimespan(request.Timeout, settings.Timeout, TimeSpan.FromMinutes(10));

            var retry = request.Retry ?? settings.Retry ?? 0;

            var failurePercentThresholdPercent = EmptyAlternative(settings.FailurePercentThreshold, 50);

            var failureThreshold = failurePercentThresholdPercent / 100d;

            var samplingDuration = AppliedTimespan(settings.SamplingDuration, TimeSpan.FromMilliseconds(1000));

            var minThroughput = settings.MinimumThroughput ?? 5;

            var durationOfBreak = AppliedTimespan(settings.DurationOfBreak, TimeSpan.FromMilliseconds(500));

            if (CircuitBreakerLog.IsTraceEnabled)
            {
                CircuitBreakerLog.LogTrace($@"RequestId:{request.RequestId}
                                        |AppName:{request.Context.GetAppName()}
                                        |ServiceName:{request.Context.GetServiceName()}
                                        |CircuitKey:{request.CircuitKey}
                                        |Request.Retry:{request.Retry}
                                        |Request.Timeout:{request.Timeout}
                                        |Settings.Retry:{settings.Retry}
                                        |Settings.Timeout:{settings.Timeout}
                                        |Settings.FailureThreshold:{failureThreshold}
                                        |Settings.SamplingDuration:{samplingDuration}
                                        |Settings.MinThroughput:{minThroughput}
                                        |Settings.DurationOfBreak:{durationOfBreak}
                                        |Settings.MaxParallelization:{maxParallelization}
                                        |Settings.MaxQueingActions:{maxQueingActions}");
            }

            var bulkHead = Policy.BulkheadAsync(maxParallelization, maxQueingActions);

            var timeoutPolicy = Policy.TimeoutAsync(timeout, Polly.Timeout.TimeoutStrategy.Pessimistic);

            var retryPolicy = Policy.Handle <Exception>().RetryAsync(retry);

            var circuit = Policy.Handle <Exception>()
                          .AdvancedCircuitBreakerAsync(failureThreshold,
                                                       samplingDuration,
                                                       minThroughput,
                                                       durationOfBreak);

            return(circuit.WrapAsync(bulkHead.WrapAsync(retryPolicy.WrapAsync(timeoutPolicy))));
        }
コード例 #30
0
        public Task DownloadThemAllAsync(IEnumerable <Uri> uris, ProcessResult processResult, byte maxThreads)
        {
            var throttler = Policy.BulkheadAsync(maxThreads, int.MaxValue); //!SPOT: maxQueuingActions param can cause BulkheadRejectedException

            //Single Producer
            //Waiting for all workers to finish
            return(Task.WhenAll(
                       uris.Select(                       //Multiple Workers
                           url => throttler.ExecuteAsync( //MaxDegreeOfParallelism
                               async() => await WorkerAsync(url, processResult)
                               ))));
        }