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))); }
/// <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 }); }
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)) ); }
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); }
/// <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); }
// 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>(); }
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; })); }
public virtual PolicyWrapper <HttpResponseMessage> Build() { return(new PolicyWrapper <HttpResponseMessage> { Policy = Policy.BulkheadAsync <HttpResponseMessage>(MaxParallelization, QueueSize) }); }
/// <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); }
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); } }
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); }
/// <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); }
/// <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); }
// 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); }
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)); }
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) =>
// 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(); }
// 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>(); }
private AsyncBulkheadPolicy <HttpResponseMessage> BulkheadPolicy() { var bulkhead = Policy .BulkheadAsync <HttpResponseMessage>(_options.Bulkhead.MaxParallelization, _options.Bulkhead.MaxQueuingActions); return(bulkhead); }
public PollyTraining() { _proxy = Policy.BulkheadAsync(2, 1, c => { Console.WriteLine("reject request"); return(Task.CompletedTask); }); }
public void Should_throw_when_onBulkheadRejected_is_null() { Action policy = () => Policy .BulkheadAsync(1, 0, null); policy.ShouldThrow <ArgumentNullException>().And .ParamName.Should().Be("onBulkheadRejectedAsync"); }
public void Should_throw_when_maxQueuingActions_less_than_zero() { Action policy = () => Policy .BulkheadAsync(1, -1); policy.ShouldThrow <ArgumentOutOfRangeException>().And .ParamName.Should().Be("maxQueuingActions"); }
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"); }
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); }
/// <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)); }
// 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) })); }
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) ); }
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(); }
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)))); }
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) )))); }