//exponential backoff approach. => if you can not find the service try 5 times, and each time wait for 2 power of last waiting time value. private IAsyncPolicy <HttpResponseMessage> GetRetryPolicy() { return(HttpPolicyExtensions.HandleTransientHttpError().OrResult(response => response.StatusCode == HttpStatusCode.NotFound) .WaitAndRetryAsync(retryCount: 5, sleepDurationProvider: retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)))); }
public async Task <DeveloperApiKeyResult> GetApiKeyOrNullAsync(bool invalidateCache = false) { if (!AuthService.IsLoggedIn()) { return(null); } if (invalidateCache) { _apiKeyResult = null; } if (_apiKeyResult != null) { return(_apiKeyResult); } var url = $"{CliUrls.WwwAbpIo}api/license/api-key"; using (var client = new CliHttpClient()) { var response = await HttpPolicyExtensions .HandleTransientHttpError() .OrResult(msg => !msg.IsSuccessStatusCode) .WaitAndRetryAsync(new[] { TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(7) }, (responseMessage, timeSpan, retryCount, context) => { if (responseMessage.Exception != null) { _logger.LogWarning( $"{retryCount}. request attempt failed to {url} with an error: \"{responseMessage.Exception.Message}\". " + $"Waiting {timeSpan.TotalSeconds} secs for the next try..."); } else if (responseMessage.Result != null) { _logger.LogWarning( $"{retryCount}. request attempt failed {url} with {(int)responseMessage.Result.StatusCode}-{responseMessage.Result.ReasonPhrase}. " + $"Waiting {timeSpan.TotalSeconds} secs for the next try..."); } }) .ExecuteAsync(async() => await client.GetAsync(url).ConfigureAwait(false)).ConfigureAwait(false); if (!response.IsSuccessStatusCode) { throw new Exception($"ERROR: Remote server returns '{response.StatusCode}'"); } await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(response).ConfigureAwait(false); var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); var apiKeyResult = JsonSerializer.Deserialize <DeveloperApiKeyResult>(responseContent); return(apiKeyResult); } }
static IAsyncPolicy <HttpResponseMessage> GetCircuitBreakerPolicy() { return(HttpPolicyExtensions .HandleTransientHttpError() .CircuitBreakerAsync(5, TimeSpan.FromSeconds(30))); }
public static IAsyncPolicy <HttpResponseMessage> GetWaitAndRetryForeverPolicy() => HttpPolicyExtensions .HandleTransientHttpError() .WaitAndRetryForeverAsync(retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
private static IAsyncPolicy <HttpResponseMessage> GetCircuitBreakerPolicy() { return(HttpPolicyExtensions .HandleTransientHttpError() .CircuitBreakerAsync(2, TimeSpan.FromSeconds(30))); //After two times falls it will not retry until 30 sec. }
private static IAsyncPolicy <HttpResponseMessage> GetRetryPolicy() { return(HttpPolicyExtensions .HandleTransientHttpError() .WaitAndRetryAsync(retryCount: 6, sleepDurationProvider: retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)))); }
internal HttpClientFactoryConfigurator(ILogger logger) { var retryPolicy = HttpPolicyExtensions .HandleTransientHttpError() .Or <TimeoutRejectedException>() // thrown by Polly's TimeoutPolicy if the inner call times out .WaitAndRetryAsync(new[] { TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(10) }, onRetry: (r, ts, n, ctx) => { if (r.Result == default) // no result, an exception was thrown { logger.LogError(r.Exception, $"Retry[{n}]: {r.Exception.Message}"); } else { logger.LogError($"Retry[{n}]: ({r.Result.StatusCode}) {r.Result.ReasonPhrase}"); } }); var timeoutPolicy = Policy.TimeoutAsync <HttpResponseMessage>(20); // Timeout for an individual try var circuitBreakerPolicy = HttpPolicyExtensions .HandleTransientHttpError() .CircuitBreakerAsync( handledEventsAllowedBeforeBreaking: 3, durationOfBreak: TimeSpan.FromSeconds(30), onBreak: (r, ts, ctx) => { if (r.Result == default) // no result, an exception was thrown { logger.LogError(r.Exception, $"Circuit Breaking: {r.Exception.Message}"); } else { logger.LogError($"Circuit Breaking: ({r.Result.StatusCode}) {r.Result.ReasonPhrase}"); } }, onReset: ctx => { logger.LogWarning($"Circuit Resetting..."); }); ServiceProvider = new ServiceCollection() .AddHttpClient("snapshot", client => { //client.Timeout = Timeout.InfiniteTimeSpan; // default: 100 seconds client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); //client.DefaultRequestVersion = new Version(2, 0); }) .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler() { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate, AllowAutoRedirect = false, //MaxConnectionsPerServer = 1 // The default: int.MaxValue }) //.SetHandlerLifetime(Timeout.InfiniteTimeSpan) // default: 2 minutes .AddPolicyHandler(retryPolicy) .AddPolicyHandler(timeoutPolicy) .AddPolicyHandler(circuitBreakerPolicy) .Services .AddHttpClient("history", client => { //client.Timeout = Timeout.InfiniteTimeSpan; // default: 100 seconds client.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36"); }) .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler() { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate, AllowAutoRedirect = false, CookieContainer = new CookieContainer(), //MaxConnectionsPerServer = 1 // The default: int.MaxValue }) //.SetHandlerLifetime(Timeout.InfiniteTimeSpan) // default: 2 minutes .AddPolicyHandler(retryPolicy) .AddPolicyHandler(timeoutPolicy) .AddPolicyHandler(circuitBreakerPolicy) .Services .BuildServiceProvider(); }
private IAsyncPolicy <HttpResponseMessage> GetRetryPolicy() { return(HttpPolicyExtensions .HandleTransientHttpError() .WaitAndRetryAsync(10, retryTime => TimeSpan.FromSeconds(3))); }
private static IAsyncPolicy <HttpResponseMessage> GetCircuitBreakerPolicy() => HttpPolicyExtensions.HandleTransientHttpError().CircuitBreakerAsync(CircuitBreakAttempt, DurationOfCircuitBreak);
public void ConfigureServices(IServiceCollection services) { services.AddSingleton <IHttpContextAccessor, HttpContextAccessor>(); services.AddControllers() .AddNewtonsoftJson(options => { options.SerializerSettings.Converters.Add(new StringEnumConverter()); options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; }); services.AddOData(); services.AddOptions(); services.AddMemoryCache(); #if (!CacheExists) services.AddDistributedMemoryCache(); #endif #if (CacheSqlServer) services.AddDistributedSqlServerCache(options => { options.ConnectionString = Configuration.GetConnectionString(Configuration.GetValue <string>("Cache:SqlServer:ConnectionStringKey")); options.SchemaName = Configuration.GetValue <string>("Cache:SqlServer:SchemaName"); options.TableName = Configuration.GetValue <string>("Cache:SqlServer:TableName"); }); #endif #if (CacheRedis) services.AddStackExchangeRedisCache(options => { options.Configuration = Configuration.GetConnectionString(Configuration.GetValue <string>("Cache:Redis:ConnectionStringKey")); options.InstanceName = Configuration.GetValue <string>("Cache:Redis:InstanceName"); //x Configuration.GetSection("Cache:Redis").Bind(options); options.ConfigurationOptions = ConfigurationOptions.Parse(options.Configuration); options.ConfigurationOptions.AbortOnConnectFail = true; }); #endif #if (EntityFramework) const string databaseConnectionString = "MsSqlConnection"; string connectionString = Configuration.GetConnectionString(databaseConnectionString); string assemblyName = Configuration.GetValue(typeof(string) , DbContextFactory.MigrationAssemblyNameConfiguration) .ToString(); services.AddDbContext <BurcinDatabaseDbContext>(options => options.UseSqlServer(connectionString , sqlServerOptions => { sqlServerOptions.MigrationsAssembly(assemblyName); sqlServerOptions.EnableRetryOnFailure(5 , TimeSpan.FromSeconds(30) , null); })); #endif #if (BackgroundService) services.AddGracePeriodManagerService(Configuration); #endif services.AddHelper(Configuration); services.TryAddEnumerable(ServiceDescriptor.Singleton <MatcherPolicy, DomainMatcherPolicy.DomainMatcherPolicy>()); services.AddResponseCaching(); services.AddResponseCompression(); #if (Swagger) services.AddSwaggerGen(options => { options.IgnoreObsoleteActions(); options.IgnoreObsoleteProperties(); options.SwaggerDoc("v1" , new OpenApiInfo { Title = "Burcin API" , Version = "1.0" , Description = "Burcin API" }); // Set the comments path for the Swagger JSON and UI. string xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; string xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); options.IncludeXmlComments(xmlPath); }); // Workaround: https://github.com/OData/WebApi/issues/1177 SetOutputFormatters(services); #endif #if (BlazorApplication) services.AddRazorPages(); services.AddServerSideBlazor(); services.AddScoped <ChefService>(); services.AddSingleton <WeatherForecastService>(); #endif services.AddGoogleStorageService(Configuration); #if (BlazorApplication || HealthChecks) AsyncRetryPolicy <HttpResponseMessage> retryPolicy = HttpPolicyExtensions .HandleTransientHttpError() .Or <TimeoutRejectedException>() .RetryAsync(5); services.AddHttpClient("Remote Services").AddPolicyHandler(retryPolicy); #endif #if (HealthChecks) services.AddSingleton <CustomHealthCheck>(); services.AddHealthChecks() .AddCheck <CustomHealthCheck>(CustomHealthCheck.HealthCheckName , failureStatus: HealthStatus.Degraded , tags: new[] { "ready" }) .AddCheck <SlowDependencyHealthCheck>(SlowDependencyHealthCheck.HealthCheckName , failureStatus: null , tags: new[] { "ready" }) .AddAsyncCheck(name: "long_running" , check: async cancellationToken => { await Task.Delay(TimeSpan.FromSeconds(5) , cancellationToken); return(HealthCheckResult.Healthy("OK")); } , tags: new[] { "self" }) .AddWorkingSetHealthCheck((long)Ruya.Primitives.Constants.GigaByte * 1 , name: "Memory (WorkingSet)" , failureStatus: HealthStatus.Degraded , tags: new[] { "self" }) .AddDiskStorageHealthCheck(check => { check.AddDrive(DriveInfo.GetDrives().First().Name , 1024); } , name: "Disk Storage" , failureStatus: HealthStatus.Degraded , tags: new[] { "self" }) .AddDnsResolveHealthCheck(setup => setup.ResolveHost("burcin.local") , name: "DNS" , failureStatus: HealthStatus.Degraded , tags: new[] { "self" }) .AddPingHealthCheck(setup => setup.AddHost("burcin.local" , (int)TimeSpan.FromSeconds(3) .TotalMilliseconds) , name: "Ping" , failureStatus: HealthStatus.Degraded , tags: new[] { "3rdParty" }) .AddUrlGroup(new[] { new Uri("https://burcin.local") } , name: "Remote Urls" , failureStatus: HealthStatus.Degraded , tags: new[] { "3rdParty" }) #if (EntityFramework) // TODO: Make the `MsSqlConnection` string constant. It exists in Program.cs too. .AddSqlServer(connectionString: Configuration["ConnectionStrings:MsSqlConnection"] , name: "Microsoft SQL" , failureStatus: HealthStatus.Unhealthy , tags: new[] { "services" }) #endif #if (CacheSqlServer) .AddSqlServer(connectionString: Configuration["ConnectionStrings:MsSqlCacheConnection"] , name: "Microsoft SQL (Cache)" , failureStatus: HealthStatus.Degraded , tags: new[] { "services" }) #endif #if (CacheRedis) .AddRedis(redisConnectionString: Configuration["ConnectionStrings:RedisCacheConnection"] , name: "Redis" , failureStatus: HealthStatus.Degraded , tags: new[] { "services" }) #endif .AddRabbitMQ(rabbitConnectionString: Configuration["ConnectionStrings:RabbitMqConnection"] , name: "RabbitMq" , failureStatus: HealthStatus.Unhealthy , tags: new[] { "services" }) .AddElasticsearch(elasticsearchUri: Configuration["ConnectionStrings:ElasticSearchConnection"] , name: "ElasticSearch" , failureStatus: HealthStatus.Unhealthy , tags: new[] { "services" }) //.AddApplicationInsightsPublisher() //.AddPrometheusGatewayPublisher() //.AddSeqPublisher(options => options.Endpoint = Configuration["ConnectionStrings:SeqConnection"]) ; services.AddHealthChecksUI(); #endif }
static IAsyncPolicy <HttpResponseMessage> GetRetryPolicy() { return(HttpPolicyExtensions .HandleTransientHttpError() .WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)))); }
public static IAsyncPolicy <HttpResponseMessage> GetCircuitBreakerPolicy(int handledEventsAllowedBeforeBreaking = 5, int durationOfBreakSeconds = 30) { return(HttpPolicyExtensions .HandleTransientHttpError() .CircuitBreakerAsync(5, TimeSpan.FromSeconds(durationOfBreakSeconds))); }
static IAsyncPolicy <HttpResponseMessage> GetCircuitBreakerPolicy(CircuitBreakingSettings settings) { return(HttpPolicyExtensions .HandleTransientHttpError() .CircuitBreakerAsync(settings.ConsecutiveFaults, settings.BreakTime)); }
private static async Task Main(string[] args) { var parsingResult = Parser.Default.ParseArguments <ProgramOptions>(args); if (parsingResult is Parsed <ProgramOptions> success) { Options = success.Value; } else { return; } var jitterer = new Random(); var retryPolicy = HttpPolicyExtensions .HandleTransientHttpError() .Or <TimeoutException>() .Or <TaskCanceledException>(tex => !tex.CancellationToken.IsCancellationRequested) .Or <IOException>(iex => iex.Message.Contains("Connection reset by peer")) .WaitAndRetryAsync ( 6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)) + TimeSpan.FromMilliseconds(jitterer.Next(0, 100)) ); await using var services = new ServiceCollection() .AddHttpClient <JetbrainsPlugins, JetbrainsPlugins>() .ConfigurePrimaryHttpMessageHandler ( () => new SocketsHttpHandler { AllowAutoRedirect = true, } ) .ConfigureHttpClient ( client => { // Timeouts are handled in the handler client.Timeout = Timeout.InfiniteTimeSpan; client.DefaultRequestHeaders.UserAgent.Clear(); client.DefaultRequestHeaders.UserAgent.ParseAdd("JetBrains Rider/191.7141355"); } ) .ConfigureHttpMessageHandlerBuilder ( builder => { var rateLimitingHandler = new RateLimitingHttpHandler ( TimeLimiter.GetFromMaxCountByInterval(128, TimeSpan.FromSeconds(1)) ); var timeoutHandler = new TimeoutHttpHandler(); builder.AdditionalHandlers.Add(rateLimitingHandler); builder.AdditionalHandlers.Add(timeoutHandler); } ) .AddPolicyHandler(retryPolicy) .Services .AddSingleton <RepositoryMirrorer>() .BuildServiceProvider(); var mirrorer = services.GetRequiredService <RepositoryMirrorer>(); using var cancellationSource = new CancellationTokenSource(); await Console.Out.WriteLineAsync($"Fetching latest plugin versions for {Options.ProductVersions.Humanize()}..."); await mirrorer.MirrorRepositoriesAsync(Options.ProductVersions, cancellationSource.Token); }
public static void RegisterServices(IServiceCollection services, IHostingEnvironment environment, IConfiguration configuration) { IdentityModelEventSource.ShowPII = true; //Application services.AddScoped <IUserService, UserService>(); services.AddScoped <IUserQueryService, UserQueryService>(); services.AddScoped <IUserPreferenceService, UserPreferenceService>(); services.AddScoped <IUserActivityService, UserActivityService>(); services.AddScoped <IUserActivityQueryService, UserActivityQueryService>(); services.AddScoped <ICustomerService, CustomerService>(); services.AddScoped <ICustomerMemberService, CustomerMemberService>(); services.AddScoped <ICustomerQueryService, CustomerQueryService>(); services.AddScoped <IIdentityService, IdentityService>(); services.AddDbContext <CoreAuthDbContext>(options => options.UseLazyLoadingProxies() .UseSqlServer(configuration.GetConnectionString("DefaultConnection"), sqlServerOptionsAction: sqlOptions => { sqlOptions.EnableRetryOnFailure( maxRetryCount: 10, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); }) ); services.AddIdentity <User, IdentityRole>(o => { // SignIn settings // o.SignIn.RequireConfirmedEmail = true; // User settings o.User.RequireUniqueEmail = true; // Password settings o.Password.RequireDigit = true; o.Password.RequireLowercase = true; o.Password.RequireUppercase = true; o.Password.RequireNonAlphanumeric = true; o.Password.RequiredLength = 8; }) .AddEntityFrameworkStores <CoreAuthDbContext>() .AddDefaultTokenProviders(); services.ConfigureApplicationCookie(options => { options.LoginPath = $"/Identity/Account/Login"; options.LogoutPath = $"/Identity/Account/Logout"; options.AccessDeniedPath = $"/Identity/Account/AccessDenied"; }); var migrationsAssembly = typeof(CoreAuthDbContext).GetTypeInfo().Assembly.GetName().Name; services.AddIdentityServer(options => { options.UserInteraction.LoginUrl = "/Identity/Account/Login"; options.UserInteraction.LogoutUrl = "/Identity/Account/Logout"; options.Events.RaiseSuccessEvents = true; options.Events.RaiseFailureEvents = true; options.Events.RaiseErrorEvents = true; }) .AddDeveloperSigningCredential() .AddAspNetIdentity <User>() .AddConfigurationStore(options => { options.ConfigureDbContext = builder => builder.UseSqlServer(configuration.GetConnectionString("DefaultConnection"), sqlServerOptionsAction: sqlOptions => { sqlOptions.MigrationsAssembly(migrationsAssembly); sqlOptions.EnableRetryOnFailure( maxRetryCount: 10, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); }); }) .AddOperationalStore(options => { options.ConfigureDbContext = builder => builder.UseSqlServer(configuration.GetConnectionString("DefaultConnection"), sqlServerOptionsAction: sqlOptions => { sqlOptions.MigrationsAssembly(migrationsAssembly); sqlOptions.EnableRetryOnFailure( maxRetryCount: 10, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); }); // this enables automatic token cleanup. this is optional. options.EnableTokenCleanup = true; options.TokenCleanupInterval = 30; }); services.AddHttpContextAccessor(); services.AddHttpClient(); // Domain services.AddScoped <IDomainManagerService, DomainManagerService>(); // Infra - Data services.AddTransient <IUserRepository, UserSqlServerRepository>(); services.AddTransient <ICustomerRepository, CustomerSqlServerRepository>(); services.AddTransient <ICustomerMemberRepository, CustomerMemberSqlServerRepository>(); //Polly Policies IPolicyRegistry <string> registry = services.AddPolicyRegistry(); IAsyncPolicy <HttpResponseMessage> httpRetryPolicy = Policy.HandleResult <HttpResponseMessage>(r => !r.IsSuccessStatusCode && r.StatusCode != System.Net.HttpStatusCode.Conflict) .RetryAsync(3); registry.Add("SimpleHttpRetryPolicy", httpRetryPolicy); Random jitterer = new Random(); IAsyncPolicy <HttpResponseMessage> httWaitAndpRetryPolicy = Policy.HandleResult <HttpResponseMessage>(r => !r.IsSuccessStatusCode && r.StatusCode != System.Net.HttpStatusCode.Conflict) .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)) + TimeSpan.FromMilliseconds(jitterer.Next(0, 100))); registry.Add("SimpleWaitAndRetryPolicy", httWaitAndpRetryPolicy); IAsyncPolicy <HttpResponseMessage> noOpPolicy = Policy.NoOpAsync() .AsAsyncPolicy <HttpResponseMessage>(); registry.Add("NoOpPolicy", noOpPolicy); services.AddHttpClient("RemoteServerFromService", client => { client.DefaultRequestHeaders.Add("Accept", "application/json"); }) .AddPolicyHandlerFromRegistry((policyRegistry, httpRequestMessage) => { if (httpRequestMessage.Method == HttpMethod.Get) { return(policyRegistry.Get <IAsyncPolicy <HttpResponseMessage> >("SimpleHttpRetryPolicy")); } else if (httpRequestMessage.Method == HttpMethod.Post) { return(policyRegistry.Get <IAsyncPolicy <HttpResponseMessage> >("NoOpPolicy")); } else { return(policyRegistry.Get <IAsyncPolicy <HttpResponseMessage> >("SimpleWaitAndRetryPolicy")); } }) .AddPolicyHandler((httpRequestMessage) => { return(HttpPolicyExtensions.HandleTransientHttpError().CircuitBreakerAsync(5, TimeSpan.FromSeconds(30))); }); services.AddHttpClient("RemoteServerFromWorker", client => { client.DefaultRequestHeaders.Add("Accept", "application/json"); }) .AddPolicyHandlerFromRegistry((policyRegistry, httpRequestMessage) => { if (httpRequestMessage.Method == HttpMethod.Get) { return(policyRegistry.Get <IAsyncPolicy <HttpResponseMessage> >("SimpleHttpRetryPolicy")); } else if (httpRequestMessage.Method == HttpMethod.Post) { return(policyRegistry.Get <IAsyncPolicy <HttpResponseMessage> >("NoOpPolicy")); } else { return(policyRegistry.Get <IAsyncPolicy <HttpResponseMessage> >("SimpleWaitAndRetryPolicy")); } }) .AddPolicyHandler((httpRequestMessage) => { return(HttpPolicyExtensions.HandleTransientHttpError().CircuitBreakerAsync(5, TimeSpan.FromSeconds(30))); }); }
private static IAsyncPolicy <HttpResponseMessage> GetRetryPolicy(IServiceProvider provider) => HttpPolicyExtensions.HandleTransientHttpError() .OrResult(httpResponseMessage => GetHttpStatusCodesWorthRetrying().Contains(httpResponseMessage.StatusCode)) .WaitAndRetryAsync(RetryAttempt, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (result, timeSpan, attempt, _) => provider.GetService <ILogger <IElasticClient> >().LogWarning(GetRetryMessage(timeSpan, attempt, result)));
/// <summary> /// Policy to break the retry policy after getting same error for 2 times consecutively /// </summary> /// <returns></returns> public static IAsyncPolicy <HttpResponseMessage> GetCircuitBreakerPolicy() => HttpPolicyExtensions .HandleTransientHttpError() // Only handle 408 or 5xx errors .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.Forbidden) // Configure for additional failures .CircuitBreakerAsync(2, TimeSpan.FromSeconds(6));
public static IAsyncPolicy <HttpResponseMessage> WaitAndRetry(int retryCount = 5) => HttpPolicyExtensions .HandleTransientHttpError() .Or <HttpRequestException>() .Or <TimeoutRejectedException>() .WaitAndRetryAsync(retryCount, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
private static Polly.Retry.AsyncRetryPolicy <HttpResponseMessage> RetryPolicy(int retries) => HttpPolicyExtensions .HandleTransientHttpError() .Or <TimeoutRejectedException>() .RetryAsync(retries);
private IAsyncPolicy <HttpResponseMessage> GetCircuitBreakerPatternPolicy(HttpRequestMessage arg) { //Circuit breaket pattern to cut-off retrying to connect to a service after a given number of attempts //after return(HttpPolicyExtensions.HandleTransientHttpError().CircuitBreakerAsync(3, TimeSpan.FromSeconds(30))); }
// This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { var cosmosConfig = new CosmosConfig( _settings.CosmosSettings.DatabaseName, _settings.CosmosSettings.EndpointUri, _settings.CosmosSettings.PrimaryKey, _settings.CosmosSettings.RequestTimeoutInSeconds ); var cosmosContainers = new List <ContainerInfo>() { new ContainerInfo() { Name = "rmas", PartitionKey = "PartitionKey" } }; var avalaraConfig = new AvalaraConfig() { BaseApiUrl = _settings.AvalaraSettings.BaseApiUrl, AccountID = _settings.AvalaraSettings.AccountID, LicenseKey = _settings.AvalaraSettings.LicenseKey, CompanyCode = _settings.AvalaraSettings.CompanyCode, CompanyID = _settings.AvalaraSettings.CompanyID }; var currencyConfig = new BlobServiceConfig() { ConnectionString = _settings.BlobSettings.ConnectionString, Container = _settings.BlobSettings.ContainerNameExchangeRates }; var assetConfig = new BlobServiceConfig() { ConnectionString = _settings.BlobSettings.ConnectionString, Container = "assets", AccessType = BlobContainerPublicAccessType.Container }; var flurlClientFactory = new PerBaseUrlFlurlClientFactory(); var smartyStreetsUsClient = new ClientBuilder(_settings.SmartyStreetSettings.AuthID, _settings.SmartyStreetSettings.AuthToken).BuildUsStreetApiClient(); services .Configure <KestrelServerOptions>(options => { options.AllowSynchronousIO = true; }) .Configure <IISServerOptions>(options => { options.AllowSynchronousIO = true; }) .AddSingleton <ISimpleCache, OrderCloud.Common.Services.LazyCacheService>() // Replace LazyCacheService with RedisService if you have multiple server instances. .ConfigureServices() .AddOrderCloudUserAuth() .AddOrderCloudWebhookAuth(opts => opts.HashKey = _settings.OrderCloudSettings.WebhookHashKey) .InjectCosmosStore <LogQuery, OrchestrationLog>(cosmosConfig) .InjectCosmosStore <ReportTemplateQuery, ReportTemplate>(cosmosConfig) .AddCosmosDb(_settings.CosmosSettings.EndpointUri, _settings.CosmosSettings.PrimaryKey, _settings.CosmosSettings.DatabaseName, cosmosContainers) .Inject <IPortalService>() .Inject <ISmartyStreetsCommand>() .Inject <ICheckoutIntegrationCommand>() .Inject <IShipmentCommand>() .Inject <IOrderCommand>() .Inject <IPaymentCommand>() .Inject <IOrderSubmitCommand>() .Inject <IEnvironmentSeedCommand>() .Inject <IHSProductCommand>() .Inject <ILineItemCommand>() .Inject <IMeProductCommand>() .Inject <IHSCatalogCommand>() .Inject <ISendgridService>() .Inject <IHSSupplierCommand>() .Inject <ICreditCardCommand>() .Inject <ISupportAlertService>() .Inject <IOrderCalcService>() .Inject <IUserContextProvider>() .Inject <ISupplierApiClientHelper>() .AddSingleton <ISendGridClient>(x => new SendGridClient(_settings.SendgridSettings.ApiKey)) .AddSingleton <IFlurlClientFactory>(x => flurlClientFactory) .AddSingleton <DownloadReportCommand>() .Inject <IRMARepo>() .Inject <IZohoClient>() .AddSingleton <IZohoCommand>(z => new ZohoCommand(new ZohoClient( new ZohoClientConfig() { ApiUrl = "https://books.zoho.com/api/v3", AccessToken = _settings.ZohoSettings.AccessToken, ClientId = _settings.ZohoSettings.ClientId, ClientSecret = _settings.ZohoSettings.ClientSecret, OrganizationID = _settings.ZohoSettings.OrgID }, flurlClientFactory), new OrderCloudClient(new OrderCloudClientConfig { ApiUrl = _settings.OrderCloudSettings.ApiUrl, AuthUrl = _settings.OrderCloudSettings.ApiUrl, ClientId = _settings.OrderCloudSettings.MiddlewareClientID, ClientSecret = _settings.OrderCloudSettings.MiddlewareClientSecret, Roles = new[] { ApiRole.FullAccess } }))) .AddSingleton <IOrderCloudIntegrationsExchangeRatesClient, OrderCloudIntegrationsExchangeRatesClient>() .AddSingleton <IAssetClient>(provider => new AssetClient(new OrderCloudIntegrationsBlobService(assetConfig), _settings)) .AddSingleton <IExchangeRatesCommand>(provider => new ExchangeRatesCommand(new OrderCloudIntegrationsBlobService(currencyConfig), flurlClientFactory, provider.GetService <ISimpleCache>())) .AddSingleton <IAvalaraCommand>(x => new AvalaraCommand( avalaraConfig, new AvaTaxClient("four51_headstart", "v1", "four51_headstart", new Uri(avalaraConfig.BaseApiUrl) ).WithSecurity(_settings.AvalaraSettings.AccountID, _settings.AvalaraSettings.LicenseKey))) .AddSingleton <IEasyPostShippingService>(x => new EasyPostShippingService(new EasyPostConfig() { APIKey = _settings.EasyPostSettings.APIKey })) .AddSingleton <ISmartyStreetsService>(x => new SmartyStreetsService(_settings.SmartyStreetSettings, smartyStreetsUsClient)) .AddSingleton <IOrderCloudIntegrationsCardConnectService>(x => new OrderCloudIntegrationsCardConnectService(_settings.CardConnectSettings, _settings.EnvironmentSettings.Environment.ToString(), flurlClientFactory)) .AddSingleton <IOrderCloudClient>(provider => new OrderCloudClient(new OrderCloudClientConfig { ApiUrl = _settings.OrderCloudSettings.ApiUrl, AuthUrl = _settings.OrderCloudSettings.ApiUrl, ClientId = _settings.OrderCloudSettings.MiddlewareClientID, ClientSecret = _settings.OrderCloudSettings.MiddlewareClientSecret, Roles = new[] { ApiRole.FullAccess } })) .AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "Headstart API", Version = "v1" }); c.CustomSchemaIds(x => x.FullName); }); var serviceProvider = services.BuildServiceProvider(); services .AddApplicationInsightsTelemetry(new ApplicationInsightsServiceOptions { EnableAdaptiveSampling = false, // retain all data InstrumentationKey = _settings.ApplicationInsightsSettings.InstrumentationKey }); ServicePointManager.DefaultConnectionLimit = int.MaxValue; FlurlHttp.Configure(settings => settings.Timeout = TimeSpan.FromSeconds(_settings.FlurlSettings.TimeoutInSeconds == 0 ? 30 : _settings.FlurlSettings.TimeoutInSeconds)); // This adds retry logic for any api call that fails with a transient error (server errors, timeouts, or rate limiting requests) // Will retry up to 3 times using exponential backoff and jitter, a mean of 3 seconds wait time in between retries // https://github.com/App-vNext/Polly/wiki/Retry-with-jitter#more-complex-jitter var delay = Backoff.DecorrelatedJitterBackoffV2(medianFirstRetryDelay: TimeSpan.FromSeconds(3), retryCount: 3); var policy = HttpPolicyExtensions .HandleTransientHttpError() .OrResult(response => response.StatusCode == HttpStatusCode.TooManyRequests) .WaitAndRetryAsync(delay); FlurlHttp.Configure(settings => settings.HttpClientFactory = new PollyFactory(policy)); }
private void ConfigureServices(IServiceCollection services) { string functionDirectory = Environment.GetEnvironmentVariable("FUNCTION_DIRECTORY"); if (string.IsNullOrEmpty(functionDirectory)) { functionDirectory = Directory.GetCurrentDirectory(); } IConfigurationRoot Configuration = new ConfigurationBuilder() .SetBasePath(functionDirectory) .AddJsonFile("local.settings.json", optional: true) .AddJsonFile($"local.settings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", optional: true, reloadOnChange: true) .AddJsonFile("logging.json", optional: false) .AddJsonFile($"logging.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", optional: true, reloadOnChange: true) .AddEnvironmentVariables() .Build(); //Basic Services services.AddTransient <IPasswordGeneratorService, PasswordGeneratorService>(); services.AddTransient <IPipelineSpaceManagerService, PipelineSpaceManagerService>(); services.AddTransient <IHttpClientWrapperService, HttpClientWrapperService>(); //Polly Policies IPolicyRegistry <string> registry = services.AddPolicyRegistry(); IAsyncPolicy <HttpResponseMessage> httpRetryPolicy = Policy.HandleResult <HttpResponseMessage>(r => !r.IsSuccessStatusCode) .RetryAsync(3); registry.Add("SimpleHttpRetryPolicy", httpRetryPolicy); Random jitterer = new Random(); IAsyncPolicy <HttpResponseMessage> httWaitAndpRetryPolicy = Policy.HandleResult <HttpResponseMessage>(r => !r.IsSuccessStatusCode) .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)) + TimeSpan.FromMilliseconds(jitterer.Next(0, 100))); registry.Add("SimpleWaitAndRetryPolicy", httWaitAndpRetryPolicy); IAsyncPolicy <HttpResponseMessage> noOpPolicy = Policy.NoOpAsync() .AsAsyncPolicy <HttpResponseMessage>(); registry.Add("NoOpPolicy", noOpPolicy); services.AddHttpClient("RemoteServerFromWorker", client => { client.DefaultRequestHeaders.Add("Accept", "application/json"); }) .AddPolicyHandlerFromRegistry((policyRegistry, httpRequestMessage) => { if (httpRequestMessage.Method == HttpMethod.Get) { return(policyRegistry.Get <IAsyncPolicy <HttpResponseMessage> >("SimpleHttpRetryPolicy")); } else if (httpRequestMessage.Method == HttpMethod.Post) { return(policyRegistry.Get <IAsyncPolicy <HttpResponseMessage> >("NoOpPolicy")); } else { return(policyRegistry.Get <IAsyncPolicy <HttpResponseMessage> >("SimpleWaitAndRetryPolicy")); } }) .AddPolicyHandler((httpRequestMessage) => { return(HttpPolicyExtensions.HandleTransientHttpError().CircuitBreakerAsync(5, TimeSpan.FromSeconds(30))); }); //Handler Services services.AddTransient <ProjectVSTSHandlerService>(); services.AddTransient <ProjectBitbucketHandlerService>(); services.AddTransient <ProjectGitHubHandlerService>(); services.AddTransient <Func <DomainModels.ConfigurationManagementService, IProjectHandlerService> >(serviceProvider => key => { switch (key) { case DomainModels.ConfigurationManagementService.VSTS: return(serviceProvider.GetService <ProjectVSTSHandlerService>()); case DomainModels.ConfigurationManagementService.Bitbucket: return(serviceProvider.GetService <ProjectBitbucketHandlerService>()); case DomainModels.ConfigurationManagementService.GitHub: return(serviceProvider.GetService <ProjectGitHubHandlerService>()); default: throw new KeyNotFoundException(); } }); services.AddTransient <ProjectServiceVSTSHandlerService>(); services.AddTransient <ProjectServiceBitbucketHandlerService>(); services.AddTransient <ProjectServiceGitHubHandlerService>(); services.AddTransient <Func <DomainModels.ConfigurationManagementService, IProjectServiceHandlerService> >(serviceProvider => key => { switch (key) { case DomainModels.ConfigurationManagementService.VSTS: return(serviceProvider.GetService <ProjectServiceVSTSHandlerService>()); case DomainModels.ConfigurationManagementService.Bitbucket: return(serviceProvider.GetService <ProjectServiceBitbucketHandlerService>()); case DomainModels.ConfigurationManagementService.GitHub: return(serviceProvider.GetService <ProjectServiceGitHubHandlerService>()); default: throw new KeyNotFoundException(); } }); services.AddTransient <ProjectFeatureVSTSHandlerService>(); services.AddTransient <ProjectFeatureBitbucketHandlerService>(); services.AddTransient <ProjectFeatureGitHubHandlerService>(); services.AddTransient <Func <DomainModels.ConfigurationManagementService, IProjectFeatureHandlerService> >(serviceProvider => key => { switch (key) { case DomainModels.ConfigurationManagementService.VSTS: return(serviceProvider.GetService <ProjectFeatureVSTSHandlerService>()); case DomainModels.ConfigurationManagementService.Bitbucket: return(serviceProvider.GetService <ProjectFeatureBitbucketHandlerService>()); case DomainModels.ConfigurationManagementService.GitHub: return(serviceProvider.GetService <ProjectFeatureGitHubHandlerService>()); default: throw new KeyNotFoundException(); } }); services.AddTransient <CPSAWSService>(); services.AddTransient <CPSAzureService>(); services.AddTransient <Func <DomainModels.CloudProviderService, ICPSService> >(serviceProvider => key => { switch (key) { case DomainModels.CloudProviderService.AWS: return(serviceProvider.GetService <CPSAWSService>()); case DomainModels.CloudProviderService.Azure: return(serviceProvider.GetService <CPSAzureService>()); default: throw new KeyNotFoundException(); } }); services.AddTransient <IEventHandler <ProjectCreatedEvent>, ProjectCreatedHandler>(); services.AddTransient <IEventHandler <ProjectImportedEvent>, ProjectImportedHandler>(); services.AddTransient <IEventHandler <ProjectServiceCreatedEvent>, ProjectServiceCreatedHandler>(); services.AddTransient <IEventHandler <ProjectServiceImportedEvent>, ProjectServiceImportedHandler>(); services.AddTransient <IEventHandler <ProjectFeatureCreatedEvent>, ProjectFeatureCreatedHandler>(); services.AddTransient <IEventHandler <ProjectFeatureServiceCreatedEvent>, ProjectFeatureServiceCreatedHandler>(); services.AddTransient <IEventHandler <ProjectServiceBuildQueuedEvent>, ProjectServiceBuildQueuedHandler>(); services.AddTransient <IEventHandler <ProjectFeatureServiceBuildQueuedEvent>, ProjectFeatureServiceBuildQueuedHandler>(); services.AddTransient <IEventHandler <OrganizationDeletedEvent>, OrganizationDeletedHandler>(); services.AddTransient <IEventHandler <ProjectDeletedEvent>, ProjectDeletedHandler>(); services.AddTransient <IEventHandler <ProjectServiceDeletedEvent>, ProjectServiceDeletedHandler>(); services.AddTransient <IEventHandler <ProjectFeatureDeletedEvent>, ProjectFeatureDeletedHandler>(); services.AddTransient <IEventHandler <ProjectFeatureServiceDeletedEvent>, ProjectFeatureServiceDeletedHandler>(); services.AddTransient <IEventHandler <ProjectFeatureCompletedEvent>, ProjectFeatureCompletedHandler>(); services.AddTransient <IEventHandler <ProjectEnvironmentActivatedEvent>, ProjectEnvironmentActivatedHandler>(); services.AddTransient <IEventHandler <ProjectEnvironmentCreatedEvent>, ProjectEnvironmentCreatedHandler>(); services.AddTransient <IEventHandler <ProjectEnvironmentDeletedEvent>, ProjectEnvironmentDeletedHandler>(); services.AddTransient <IEventHandler <ProjectEnvironmentInactivatedEvent>, ProjectEnvironmentInactivatedHandler>(); services.AddTransient <IEventHandler <ProjectFeatureEnvironmentCreatedEvent>, ProjectFeatureEnvironmentCreatedHandler>(); services.AddTransient <IEventHandler <OrganizationUserInvitedEvent>, OrganizationUserInvitedHandler>(); services.AddTransient <IEventHandler <ProjectUserInvitedEvent>, ProjectUserInvitedHandler>(); services.AddTransient <IEventHandler <ProjectServiceTemplateCreatedEvent>, ProjectServiceTemplateCreatedHandler>(); services.AddTransient <IRealtimeService, RealtimeService>(); if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")) && Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT").Equals("production", StringComparison.InvariantCultureIgnoreCase)) { services.AddTransient <IEmailWorkerService, SendGridEmailWorkerService>(); } else { services.AddTransient <IEmailWorkerService, PostmarkEmailWorkerService>(); } services.Configure <ApplicationOptions>(options => { options.Url = Configuration["Application:Url"]; options.ClientId = Configuration["Application:ClientId"]; options.ClientSecret = Configuration["Application:ClientSecret"]; options.Scope = Configuration["Application:Scope"]; }); services.Configure <VSTSServiceOptions>(options => { options.AccessId = Configuration["VSTS:AccessId"]; options.AccessSecret = Configuration["VSTS:AccessSecret"]; options.AccountId = Configuration["VSTS:AccountId"]; options.ApiVersion = Configuration["VSTS:ApiVersion"]; }); services.Configure <FakeAccountServiceOptions>(options => { options.AccessId = Configuration["FakeVSTS:AccessId"]; options.AccessSecret = Configuration["FakeVSTS:AccessSecret"]; options.AccountId = Configuration["FakeVSTS:AccountId"]; options.ApiVersion = Configuration["FakeVSTS:ApiVersion"]; }); services.Configure <NotificationOptions>(options => { options.SendGrid = new SendGridOptions(); options.SendGrid.ApiKey = Configuration["Notification:SendGrid:ApiKey"]; options.SendGrid.From = Configuration["Notification:SendGrid:From"]; }); }
/// <summary> /// Initializes <see cref="IHost"/> with Sentry monitoring. /// </summary> public static IHost Init(Context context, string dsn) { SentrySdk.Init(context, o => { // TODO: ShouldCan be deleted once this PR is released: https://github.com/getsentry/sentry-dotnet/pull/1750/files#diff-c55d438dd1d5f3731c0d04d0f1213af4873645b1daa44c4c6e1b24192110d8f8R166-R167 // System.UnauthorizedAccessException: Access to the path '/proc/stat' is denied. o.DetectStartupTime = StartupTimeDetectionMode.Fast; #if ANDROID // TODO: Should be added OOTB o.Release = $"{AppInfo.PackageName}@{AppInfo.VersionString}+{AppInfo.BuildString}"; o.Android.AttachScreenshot = true; o.Android.ProfilingEnabled = true; o.Android.EnableAndroidSdkTracing = true; // Will double report transactions but to get profiler data #endif o.TracesSampleRate = 1.0; o.Debug = true; #if DEBUG o.Environment = "development"; #else o.DiagnosticLevel = SentryLevel.Info; #endif o.MaxBreadcrumbs = 250; o.InitCacheFlushTimeout = TimeSpan.FromSeconds(5); o.AttachStacktrace = true; o.Dsn = dsn; o.SendDefaultPii = true; // TODO: This needs to be built-in o.BeforeSend += @event => { const string traceIdKey = "TraceIdentifier"; switch (@event.Exception) { case OperationCanceledException _: return(null); case var e when e?.Data.Contains(traceIdKey) == true: @event.SetTag(traceIdKey, e.Data[traceIdKey]?.ToString() ?? "unknown"); break; } return(@event); }; // TODO: https://github.com/getsentry/sentry-dotnet/issues/1751 // o.BeforeBreadcrumb = breadcrumb // // This logger adds 3 crumbs for each HTTP request and we already have a Sentry integration for HTTP // // Which shows the right category, status code and a link // => string.Equals(breadcrumb.Category, "System.Net.Http.HttpClient.ISymbolClient.LogicalHandler") // || string.Equals(breadcrumb.Category, "System.Net.Http.HttpClient.ISymbolClient.ClientHandler") // ? null // : breadcrumb; }); var tran = SentrySdk.StartTransaction("AppStart", "activity.load"); SentrySdk.ConfigureScope(s => { s.Transaction = tran; s.AddAttachment(new ScreenshotAttachment()); }); // TODO: Where is this span? var iocSpan = tran.StartChild("container.init", "Initializing the IoC container"); var userAgent = Java.Lang.JavaSystem.GetProperty("http.agent") ?? "Android/" + typeof(Host).Assembly.GetName().Version; var host = Startup.Init(services => { var messages = new [] { // Unable to resolve host "symbol-collector.services.sentry.io": No address associated with hostname "No address associated with hostname", // Read error: ssl=0x79ea0d6988: SSL_ERROR_WANT_READ occurred. You should never see this. "You should never see this", // handshake error: ssl=0x78f5b01b48: I/O error during system call, Try again "Try again", // failed to connect to symbol-collector.services.sentry.io/35.188.18.176 (port 443) from /10.22.91.71 (port 43860) after 86400000ms: isConnected failed: ETIMEDOUT (Connection timed out) "Connection timed out", // Read error: ssl=0x77f787e308: Failure in SSL library, usually a protocol error // error:100003fc:SSL routines:OPENSSL_internal:SSLV3_ALERT_BAD_RECORD_MAC (external/boringssl/src/ssl/tls_record.cc:592 0x77f854d8c8:0x00000001) "Failure in SSL library, usually a protocol error", }; services.AddSingleton <AndroidMessageHandler>(); services.AddHttpClient <ISymbolClient, SymbolClient>() .ConfigurePrimaryHttpMessageHandler <AndroidMessageHandler>() .AddPolicyHandler((s, r) => HttpPolicyExtensions.HandleTransientHttpError() // Could be deleted if merged: https://github.com/App-vNext/Polly.Extensions.Http/pull/33 // On Android web get WebException instead of HttpResponseMessage which HandleTransientHttpError covers .Or <IOException>(e => messages.Any(m => e.Message.Contains(m))) .Or <WebException>(e => messages.Any(m => e.Message.Contains(m))) .Or <SocketTimeoutException>() .SentryPolicy(s)); services.AddSingleton <AndroidUploader>(); services.AddOptions().Configure <SymbolClientOptions>(o => { o.UserAgent = userAgent; o.BlockListedPaths.Add("/system/etc/.booking.data.aid"); o.BlockListedPaths.Add("/system/build.prop"); o.BlockListedPaths.Add("/system/vendor/bin/netstat"); o.BlockListedPaths.Add("/system/vendor/bin/swapoff"); }); services.AddOptions().Configure <ObjectFileParserOptions>(o => { o.IncludeHash = false; o.UseFallbackObjectFileParser = false; // Android only, use only ELF parser. }); }); iocSpan.Finish(); SentrySdk.ConfigureScope(s => s.SetTag("user-agent", userAgent)); return(host); }
private static IAsyncPolicy <HttpResponseMessage> GetRetryPolicy() => HttpPolicyExtensions .HandleTransientHttpError() .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.TooManyRequests) .WaitAndRetryAsync(5, retryAttempt => TimeSpan.FromMinutes(1));
private IAsyncPolicy <HttpResponseMessage> GetRetryPolicy() { return(HttpPolicyExtensions.HandleTransientHttpError(). OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound). WaitAndRetryAsync(10, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)))); }
public static IAsyncPolicy <HttpResponseMessage> Basic(int allowedUnsuccessfulCalls, int durationOfBreakInSeconds) => HttpPolicyExtensions.HandleTransientHttpError() .Or <TaskCanceledException>() .Or <TimeoutException>() .CircuitBreakerAsync(allowedUnsuccessfulCalls, TimeSpan.FromSeconds(durationOfBreakInSeconds), (result, breakDuration) => throw new BrokenCircuitException("Service inoperative. Circuit is open"),
/// <summary> /// 熔断策略 /// </summary> public static IAsyncPolicy <HttpResponseMessage> GetCircuitBreakerPolicy() { return(HttpPolicyExtensions .HandleTransientHttpError() // System.Net.Http.HttpRequestException情况 .CircuitBreakerAsync(5, TimeSpan.FromSeconds(30))); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.Configure <CookiePolicyOptions>( options => { // This lambda determines whether user consent for non-essential cookies is needed for a given request. options.CheckConsentNeeded = context => true; options.MinimumSameSitePolicy = SameSiteMode.None; }); services.AddAuthentication(AzureADDefaults.AuthenticationScheme) .AddAzureAD(options => this.configuration.Bind("AzureAd", options)); services.AddAuthentication(AzureADDefaults.JwtBearerAuthenticationScheme) .AddAzureADBearer(options => this.configuration.Bind("AzureAd", options)); AADAuthHelper.AdminList = this.configuration["ISVPortal:AdminAccounts"].Split(';', StringSplitOptions.RemoveEmptyEntries); AADAuthHelper.AdminTenantId = this.configuration["ISVPortal:AdminTenant"]; services.Configure <JwtBearerOptions>(AzureADDefaults.JwtBearerAuthenticationScheme, options => { // This is a Microsoft identity platform web API. options.Authority += "/v2.0"; // The web API accepts as audiences both the Client ID (options.Audience) and api://{ClientID}. options.TokenValidationParameters.ValidAudiences = new[] { options.Audience, $"api://{options.Audience}", this.configuration["AzureAD:ClientId"], $"api://{this.configuration["AzureAD:ClientId"]}" }; options.ClaimsIssuer = @"https://sts.windows.net/{tenantid}/"; // Instead of using the default validation (validating against a single tenant, // as we do in line-of-business apps), // we inject our own multitenant validation logic (which even accepts both v1 and v2 tokens). options.TokenValidationParameters.IssuerValidator = AadIssuerValidator.GetIssuerValidator(options.Authority).Validate; }); services.Configure <CookieAuthenticationOptions>( AzureADDefaults.CookieScheme, options => options.AccessDeniedPath = "/Subscriptions/NotAuthorized"); services.Configure <OpenIdConnectOptions>( AzureADDefaults.OpenIdScheme, options => { //options.Authority = options.Authority + "/v2.0/"; // Azure AD v2.0 options.TokenValidationParameters.ValidateIssuer = false; // accept several tenants (here simplified) }); services.Configure <DashboardOptions>(this.configuration.GetSection("Dashboard")); services.Configure <AzureOptions>(this.configuration.GetSection("Azure")); services.Configure <ApiBehaviorOptions>(x => { x.InvalidModelStateResponseFactory = context => { var problemDetails = new ErrorModel(context); return(new BadRequestObjectResult(problemDetails) { ContentTypes = { "application/problem+json", "application/problem+xml" } }); }; }); services.AddOptions <SecuredFulfillmentClientConfiguration>().Configure( options => { this.configuration.Bind("FulfillmentClient", options); this.configuration.Bind("SecuredCredentials:Marketplace", options); } ); services.AddHttpClient <IFulfillmentClient, FulfillmentClient>() .SetHandlerLifetime(TimeSpan.FromMinutes(5)) //Set lifetime to five minutes .AddPolicyHandler( (services, request) => HttpPolicyExtensions.HandleTransientHttpError() .OrResult(msg => ExceptionUtils.IsHttpErrorCodeRetryable(msg.StatusCode)) .WaitAndRetryAsync( 3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), onRetry: (result, timeSpan, retryCount, context) => { if (result.Exception != null) { services.GetService <ILogger <IFulfillmentClient> >()? .LogWarning($"An exception occurred on retry {retryCount} at {context.OperationKey} with message {result.Exception.Message}"); } else { services.GetService <ILogger <IFulfillmentClient> >()? .LogError($"An unsuccessful status code {result.Result.StatusCode} was received on retry {retryCount} at {context.OperationKey}"); } } )); // Hack to save the host name and port during the handling the request. Please see the WebhookController and ContosoWebhookHandler implementations services.AddSingleton <ContosoWebhookHandlerOptions>(); services.TryAddScoped <IWebhookProcessor, WebhookProcessor>(); services.TryAddScoped <IFulfillmentManager, FulfillmentManager>(); // Register the provisioning client services.AddOptions <SecuredProvisioningClientConfiguration>().Configure( options => { this.configuration.Bind("ProvisioningClient", options); this.configuration.Bind("SecuredCredentials:ResourceManager", options); } ); //services.TryAddScoped<IProvisioningClient, ProvisioningClient>(); services.AddHttpClient <IProvisioningClient, ProvisioningClient>() .SetHandlerLifetime(TimeSpan.FromMinutes(5)); services.AddHttpClient <ICustomMeteringClient, CustomMeteringClient>(); // Get the connection string from appsettings.json string connectionString = this.configuration.GetValue <string>(this.configuration["SecuredCredentials:Database:ConnectionString"]); // Database context must be registered with the dependency injection (DI) container services.AddDbContext <SqlDbContext>(options => options.UseSqlServer(connectionString)); // Register the db context interface services.TryAddScoped <ISqlDbContext, SqlDbContext>(); services.AddOptions <StorageAccountConfigurationOption>().Configure( options => { this.configuration.Bind("SecuredCredentials:StorageAccount", options); } ); // Register the storage utility interface services.TryAddScoped <IStorageUtility, StorageUtility>(); services.TryAddScoped <IKeyVaultHelper, KeyVaultHelper>(); // Register the provisioning helper services.TryAddScoped <IMarketplaceNotificationHandler, ProvisioningHelper>(); // Register the entity services services.TryAddScoped <IOfferService, OfferService>(); services.TryAddScoped <IArmTemplateService, ArmTemplateService>(); services.TryAddScoped <IPlanService, PlanService>(); services.TryAddScoped <ISubscriptionService, SubscriptionService>(); services.TryAddScoped <IAadSecretTmpService, AadSecretTmpService>(); services.TryAddScoped <IArmTemplateParameterService, ArmTemplateParameterService>(); services.TryAddScoped <ICustomMeterService, CustomMeterService>(); services.TryAddScoped <ICustomMeterDimensionService, CustomMeterDimensionService>(); services.TryAddScoped <IIpConfigService, IpConfigService>(); services.TryAddScoped <IOfferParameterService, OfferParameterService>(); services.TryAddScoped <IRestrictedUserService, RestrictedUserService>(); services.TryAddScoped <IWebhookService, WebhookService>(); services.TryAddScoped <IWebhookParameterService, WebhookParameterService>(); services.TryAddScoped <IProvisioningService, ProvisioningService>(); services.TryAddScoped <IIpAddressService, IpAddressService>(); services.TryAddScoped <ISubscriptionParameterService, SubscriptionParameterService>(); services.TryAddScoped <IWebhookWebhookParameterService, WebhookWebhookParameterService>(); services.TryAddScoped <IArmTemplateArmTemplateParameterService, ArmTemplateArmTemplateParameterService>(); services.TryAddScoped <ITelemetryDataConnectorService, TelemetryDataConnectorService>(); services.TryAddScoped <ISubscriptionCustomMeterUsageService, SubscriptionCustomMeterUsageService>(); services.TryAddScoped <ICustomMeterEventService, CustomMeterEventService>(); // Register luna db client services.AddHttpClient("Luna", x => { x.BaseAddress = new Uri(configuration.GetValue <string>("LunaClient:BaseUri")); }); services.TryAddScoped <LunaClient>(); services.AddCors(); services.AddRazorPages(); services.AddApiVersioning(o => { DateTime groupVersion = DateTime.ParseExact(apiVersion, "yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture); ApiVersion latest = new ApiVersion(groupVersion); o.ReportApiVersions = true; o.AssumeDefaultVersionWhenUnspecified = true; o.DefaultApiVersion = latest; o.Conventions.Controller <OfferController>().HasApiVersion(latest); o.Conventions.Controller <ArmTemplateController>().HasApiVersion(latest); o.Conventions.Controller <PlanController>().HasApiVersion(latest); o.Conventions.Controller <SubscriptionController>().HasApiVersion(latest); o.Conventions.Controller <ArmTemplateParameterController>().HasApiVersion(latest); o.Conventions.Controller <CustomMeterController>().HasApiVersion(latest); o.Conventions.Controller <CustomMeterDimensionController>().HasApiVersion(latest); o.Conventions.Controller <IpConfigController>().HasApiVersion(latest); o.Conventions.Controller <OfferParameterController>().HasApiVersion(latest); o.Conventions.Controller <RestrictedUserController>().HasApiVersion(latest); o.Conventions.Controller <WebhookController>().HasApiVersion(latest); o.Conventions.Controller <WebhookParameterController>().HasApiVersion(latest); }); // Register the Swagger generator, defining 1 or more Swagger documents services.AddSwaggerGen(c => { c.SwaggerDoc(apiVersion, new OpenApiInfo { Title = "Luna Dashboard API", Version = apiVersion }); // 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); }); services.AddApplicationInsightsTelemetry(); }
public TransientRetryHandler(Func <PolicyBuilder <HttpResponseMessage>, IAsyncPolicy <HttpResponseMessage> > configurePolicy) : base(configurePolicy(HttpPolicyExtensions.HandleTransientHttpError())) { }
// circuit braker approach : if you get http error, try the request for 3 times and if you still have problems,after 30 secs break all requests to this service. private IAsyncPolicy <HttpResponseMessage> GetCircuitBreakerPatternPolicy() { return(HttpPolicyExtensions.HandleTransientHttpError().CircuitBreakerAsync(handledEventsAllowedBeforeBreaking: 3, TimeSpan.FromSeconds(30))); }