-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #26 from atidev/add-httpclient-extensions
add http client handlers
- Loading branch information
Showing
10 changed files
with
171 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
using System.Threading; | ||
using ATI.Services.Common.Options; | ||
using JetBrains.Annotations; | ||
using Microsoft.Extensions.DependencyInjection; | ||
|
||
namespace ATI.Services.Consul.Http; | ||
|
||
[PublicAPI] | ||
public static class HttpClientBuilderExtensions | ||
{ | ||
public static IHttpClientBuilder WithConsul<TServiceOptions>(this IHttpClientBuilder httpClientBuilder) | ||
where TServiceOptions : BaseServiceOptions | ||
{ | ||
httpClientBuilder.Services.AddSingleton<HttpConsulHandler<TServiceOptions>>(); | ||
|
||
return httpClientBuilder | ||
.AddHttpMessageHandler<HttpConsulHandler<TServiceOptions>>() | ||
// By default, handlers are alive for 2 minutes | ||
// If we don't set InfiniteTimeSpan, every 2 minutes HttpConsulHandler will be recreated | ||
// And it will lead to new ConsulServiceAddress instances, which constructor is pretty expensive and will stop http requests for some time | ||
.SetHandlerLifetime(Timeout.InfiniteTimeSpan); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
using System; | ||
using System.Net.Http; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using ATI.Services.Common.Logging; | ||
using ATI.Services.Common.Metrics; | ||
using ATI.Services.Common.Options; | ||
using Microsoft.Extensions.Options; | ||
using NLog; | ||
|
||
namespace ATI.Services.Consul.Http; | ||
|
||
public class HttpConsulHandler<T> : HttpConsulHandler where T : BaseServiceOptions | ||
{ | ||
public HttpConsulHandler(MetricsFactory metricsFactory, IOptions<T> serviceOptions) | ||
: base(metricsFactory, serviceOptions.Value) | ||
{ | ||
} | ||
} | ||
|
||
public class HttpConsulHandler : DelegatingHandler | ||
{ | ||
private readonly ConsulServiceAddress _serviceAddress; | ||
private static readonly ILogger Logger = LogManager.GetCurrentClassLogger(); | ||
|
||
protected HttpConsulHandler(MetricsFactory metricsFactory, BaseServiceOptions serviceOptions) | ||
{ | ||
_serviceAddress = | ||
new ConsulServiceAddress(metricsFactory, serviceOptions.ConsulName, serviceOptions.Environment); | ||
|
||
Logger.WarnWithObject("HttpConsulHandler constructor", new { serviceOptions.ServiceName }); | ||
} | ||
|
||
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken ct) | ||
{ | ||
var url = await _serviceAddress.ToHttpAsync(); | ||
var relativeUrl = request.RequestUri?.PathAndQuery; | ||
request.RequestUri = new Uri(new Uri(url), relativeUrl); | ||
|
||
return await base.SendAsync(request, ct); | ||
} | ||
|
||
protected override void Dispose(bool disposing) | ||
{ | ||
if (disposing) | ||
{ | ||
_serviceAddress?.Dispose(); | ||
} | ||
|
||
base.Dispose(disposing); | ||
} | ||
} |
65 changes: 65 additions & 0 deletions
65
ATI.Services.Consul/Http/ServiceCollectionHttpClientExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
using System; | ||
using ATI.Services.Common.Http.Extensions; | ||
using ATI.Services.Common.Options; | ||
using ATI.Services.Common.Variables; | ||
using JetBrains.Annotations; | ||
using Microsoft.Extensions.Configuration; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using NLog; | ||
using ConfigurationManager = ATI.Services.Common.Behaviors.ConfigurationManager; | ||
|
||
namespace ATI.Services.Consul.Http; | ||
|
||
[PublicAPI] | ||
public static class ServiceCollectionHttpClientExtensions | ||
{ | ||
/// <summary> | ||
/// Add HttpClient to HttpClientFactory with retry/cb/timeout policy | ||
/// Will add only if UseHttpClientFactory == true | ||
/// </summary> | ||
/// <param name="services"></param> | ||
/// <typeparam name="TAdapter">Type of the http adapter for typed HttpClient</typeparam> | ||
/// <typeparam name="TServiceOptions"></typeparam> | ||
/// <returns></returns>s | ||
public static IServiceCollection AddConsulHttpClient<TAdapter, TServiceOptions>(this IServiceCollection services) | ||
where TAdapter : class | ||
where TServiceOptions : BaseServiceOptions | ||
{ | ||
var className = typeof(TServiceOptions).Name; | ||
var settings = ConfigurationManager.GetSection(className).Get<TServiceOptions>(); | ||
if (settings == null) | ||
{ | ||
throw new Exception($"Cannot find section for {className}"); | ||
} | ||
|
||
if (string.IsNullOrEmpty(settings.ConsulName)) | ||
{ | ||
throw new Exception($"Class {className} has ConsulName == null while AddConsulHttpClient"); | ||
} | ||
|
||
var serviceName = settings.ServiceName; | ||
var logger = LogManager.GetLogger(serviceName); | ||
|
||
var serviceVariablesOptions = ConfigurationManager.GetSection(nameof(ServiceVariablesOptions)).Get<ServiceVariablesOptions>(); | ||
|
||
services.AddHttpClient<TAdapter>(httpClient => | ||
{ | ||
// We will override this url by consul, but we need to set it, otherwise we will get exception because HttpRequestMessage doesn't have baseUrl (only relative) | ||
httpClient.BaseAddress = new Uri("http://localhost"); | ||
httpClient.SetBaseFields(serviceVariablesOptions.GetServiceAsClientName(), serviceVariablesOptions.GetServiceAsClientHeaderName(), settings.AdditionalHeaders); | ||
}) | ||
.WithLogging<TServiceOptions>() | ||
.WithProxyFields<TServiceOptions>() | ||
.AddRetryPolicy(settings, logger) | ||
// Get new instance url for each retry (because 1 instance can be down) | ||
.WithConsul<TServiceOptions>() | ||
.AddHostSpecificCircuitBreakerPolicy(settings, logger) | ||
.AddTimeoutPolicy(settings.TimeOut) | ||
.WithMetrics<TServiceOptions>(); | ||
// we don't override PooledConnectionLifetime even we use HttpClient in static TAdapter | ||
// because we are getting new host from consul for each request | ||
// https://learn.microsoft.com/en-us/dotnet/fundamentals/networking/http/httpclient-guidelines | ||
|
||
return services; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters