based on the article https://learn.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests
// in startup.cs
builder.Services.AddHttpClient<ICatalogService, CatalogService>()
.SetHandlerLifetime(TimeSpan.FromMinutes(5));
// usage
public class CatalogService : ICatalogService
{
private readonly HttpClient _httpClient;
private readonly string _remoteServiceBaseUrl;
public CatalogService(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<Catalog> GetCatalogItems(int page, int take, int? brand, int? type)
{
var uri = API.Catalog.GetAllCatalogItems(_remoteServiceBaseUrl,
page, take, brand, type);
var responseString = await _httpClient.GetStringAsync(uri); // <------------------
var catalog = JsonConvert.DeserializeObject<Catalog>(responseString);
return catalog;
}
}
can I say after await _httpClient.GetStringAsync(uri):
A. The underlying TCP connection is not closed, no FIN packet has been sent to the server
B. After 5mins, the TCP connection will be closed, so FIN packet is sent to the server, but still there will be around 4 mins TIME_Wait period for it (twice the maximum segment lifetime which is 2mins by default), so the TCP connectio is actually closed after 9 mins?
is my understanding on A and B correct?
If you want to have more control about the underlying sockets' lifecycle then I would suggest to specify the
PooledConnectionIdleTimeoutand/orPooledConnectionLifetimeof theSocketsHttpHandler:UPDATE #1
Using a long-living
HttpClientis different then usingHttpClientFactorywith short-livingHttpMessageHandlers.Your question is about the second case so, lets stick with that.
If you don't specify the
HandlerLifetimethen it will use 2 minutes as a default value. If you set it explicitly like you did via theSetHandlerLifetimethen it will use thatTimeSpanas the activity tracking period.Inside the
DefaultHttpClientFactorythere is a method calledCreateHandlerEntrywhich will call the following method:The
ActiveHandlerTrackingEntrywill use a simple timer to track the elapsed period without activity. It does not bother the handler directly.Rather it allows to the callers of the
StartExpiryTimermethod to specify aTimerCallback. TheDefaultHttpClientFactorypasses theExpiryTimer_Tickdelegate.This method simply removes the handler from the active handlers and moves that into the expired handlers queue (there might be outstanding/pending requests still).
The
CleanupTimer_Tickwill take care of the expired handlers. It willDisposetheActiveHandlerTrackingEntry'sInnerHandler, which is a marker class calledLifetimeTrackingHttpMessageHandler.Gladly that lengthy named handler receives the actual message handler as its constructor parameter. That received message handler is generated via a
HttpMessageHandlerBuilderclass. In case of theDefaultHttpClientFactorythis will be theDefaultHttpMessageHandlerBuilder. That class uses theHttpClientHandlernot theSocketsHttpHandleras its primary message handler.Depending on the
TARGET_BROWSERthe underlying handler will be either theBrowserHttpHandleror theSocketsHttpHandler...
My point here (as it was said by others in the comments section) is that the
HttpClientFactoryis at a much higher abstraction level than the actual TCP messages. If you search forFINorTIME_WAITmessages then you will only find thetcp_fsm.h.My advice here is that if you really care about the TCP messages then use TCPView to scrunatize the underlying communication. It might require several experiments to see how certain method calls changes the underlying connection lifecycle.