diff options
author | jolex007 <[email protected]> | 2025-05-27 18:54:54 +0300 |
---|---|---|
committer | jolex007 <[email protected]> | 2025-05-27 19:29:11 +0300 |
commit | b4ff97c0d50822d1c9164bf623326539e433d9fd (patch) | |
tree | b3db3d9ca19dbf59b16c9de2e62463e4cefb4364 /library/cpp/http | |
parent | 26998e19abe5f37265e1b083713189e28960e4e1 (diff) |
Fixed time waits
ПР про избавление от застревающих портов в состоянии TIME\_WAIT
Этот клиент используется в universal\_fetcher-е, который в свою очередь используется для скачивания резалтов с distbuild-а. Соотвественно так как он качает слишком быстро, то на хосте заканчивается кол-во эфемерных портов (потому что порты после закрытых соединений остаются в состоянии TIME\_WAIT). Эту проблему можно решить, если дожидаться закрытия соединения со стороны сервера.
В этом ПР-е сделан карантин connection-ов, который позволяет асинхронно дожидаться закрытия со стороны сервера
commit_hash:80ac8208e4efa8bc9eccbcfe20869899d8e11c5a
Diffstat (limited to 'library/cpp/http')
-rw-r--r-- | library/cpp/http/simple/http_client.cpp | 42 | ||||
-rw-r--r-- | library/cpp/http/simple/http_client.h | 19 | ||||
-rw-r--r-- | library/cpp/http/simple/http_client_options.h | 20 | ||||
-rw-r--r-- | library/cpp/http/simple/ya.make | 1 |
4 files changed, 74 insertions, 8 deletions
diff --git a/library/cpp/http/simple/http_client.cpp b/library/cpp/http/simple/http_client.cpp index 6fb04755391..87bbabc3f83 100644 --- a/library/cpp/http/simple/http_client.cpp +++ b/library/cpp/http/simple/http_client.cpp @@ -6,15 +6,25 @@ #include <util/string/cast.h> #include <util/string/join.h> #include <util/string/split.h> +#include <util/system/spinlock.h> +#include <library/cpp/cache/cache.h> + + +TSpinLock TKeepAliveHttpClient::ConnectionQuarantineMutex; +TQueue<THolder<NPrivate::THttpConnection>> TKeepAliveHttpClient::ConnectionQuarantine; TKeepAliveHttpClient::TKeepAliveHttpClient(const TString& host, ui32 port, TDuration socketTimeout, - TDuration connectTimeout) + TDuration connectTimeout, + bool useKeepAlive, + bool useConnectionPool) : Host(CutHttpPrefix(host)) , Port(port) , SocketTimeout(socketTimeout) , ConnectTimeout(connectTimeout) + , UseKeepAlive(useKeepAlive) + , UseConnectionPool(useConnectionPool) , IsHttps(host.StartsWith("https")) , IsClosingRequired(false) , HttpsVerification(TVerifyCert{Host}) @@ -159,13 +169,29 @@ bool TKeepAliveHttpClient::CreateNewConnectionIfNeeded() { ConnectTimeout, IsHttps, ClientCertificate, - HttpsVerification); + HttpsVerification, + UseKeepAlive); IsClosingRequired = false; return true; } return false; } +TKeepAliveHttpClient::~TKeepAliveHttpClient() { + if (UseConnectionPool) { + THolder<NPrivate::THttpConnection> oldConnection; + with_lock(ConnectionQuarantineMutex) { + while (ConnectionQuarantine.size() > 100) { + oldConnection = std::move(ConnectionQuarantine.front()); + + ConnectionQuarantine.pop(); + oldConnection.Reset(); + } + ConnectionQuarantine.push(std::move(Connection)); + } + } +} + THttpRequestException::THttpRequestException(int statusCode) : StatusCode(statusCode) { @@ -180,6 +206,8 @@ TSimpleHttpClient::TSimpleHttpClient(const TOptions& options) , Port(options.Port()) , SocketTimeout(options.SocketTimeout()) , ConnectTimeout(options.ConnectTimeout()) + , UseKeepAlive(options.UseKeepAlive()) + , UseConnectionPool(options.UseConnectionPool()) { } @@ -229,7 +257,8 @@ namespace NPrivate { TDuration connTimeout, bool isHttps, const TMaybe<TOpenSslClientIO::TOptions::TClientCert>& clientCert, - const TMaybe<TOpenSslClientIO::TOptions::TVerifyCert>& verifyCert) + const TMaybe<TOpenSslClientIO::TOptions::TVerifyCert>& verifyCert, + bool keepAlive) : Addr(Resolve(host, port)) , Socket(Connect(Addr, sockTimeout, connTimeout, host, port)) , SocketIn(Socket) @@ -249,8 +278,9 @@ namespace NPrivate { } else { HttpOut = MakeHolder<THttpOutput>(&SocketOut); } - - HttpOut->EnableKeepAlive(true); + if (keepAlive) { + HttpOut->EnableKeepAlive(true); + } } TNetworkAddress THttpConnection::Resolve(const TString& host, ui32 port) { @@ -292,7 +322,7 @@ TSimpleHttpClient::~TSimpleHttpClient() { } TKeepAliveHttpClient TSimpleHttpClient::CreateClient() const { - TKeepAliveHttpClient cl(Host, Port, SocketTimeout, ConnectTimeout); + TKeepAliveHttpClient cl(Host, Port, SocketTimeout, ConnectTimeout, UseKeepAlive, UseConnectionPool); if (!HttpsVerification) { cl.DisableVerificationForHttps(); diff --git a/library/cpp/http/simple/http_client.h b/library/cpp/http/simple/http_client.h index 3860862698d..87d3dc095af 100644 --- a/library/cpp/http/simple/http_client.h +++ b/library/cpp/http/simple/http_client.h @@ -8,6 +8,8 @@ #include <util/generic/strbuf.h> #include <util/generic/yexception.h> #include <util/network/socket.h> +#include <util/generic/queue.h> +#include <util/system/spinlock.h> #include <library/cpp/http/io/stream.h> #include <library/cpp/http/misc/httpcodes.h> @@ -50,7 +52,12 @@ public: TKeepAliveHttpClient(const TString& host, ui32 port, TDuration socketTimeout = TDuration::Seconds(5), - TDuration connectTimeout = TDuration::Seconds(30)); + TDuration connectTimeout = TDuration::Seconds(30), + bool useKeepAlive = true, + bool useConnectionPool = false); + + TKeepAliveHttpClient(TKeepAliveHttpClient&&) = default; + ~TKeepAliveHttpClient(); THttpCode DoGet(const TStringBuf relativeUrl, IOutputStream* output = nullptr, @@ -117,8 +124,13 @@ private: const ui32 Port; const TDuration SocketTimeout; const TDuration ConnectTimeout; + const bool UseKeepAlive; + const bool UseConnectionPool; const bool IsHttps; + static TSpinLock ConnectionQuarantineMutex; + static TQueue<THolder<NPrivate::THttpConnection>> ConnectionQuarantine; + THolder<NPrivate::THttpConnection> Connection; bool IsClosingRequired; TMaybe<TClientCert> ClientCertificate; @@ -158,6 +170,8 @@ protected: const ui32 Port; const TDuration SocketTimeout; const TDuration ConnectTimeout; + const bool UseKeepAlive = true; + const bool UseConnectionPool = false; bool HttpsVerification = false; public: @@ -215,7 +229,8 @@ namespace NPrivate { TDuration connTimeout, bool isHttps, const TMaybe<TOpenSslClientIO::TOptions::TClientCert>& clientCert, - const TMaybe<TOpenSslClientIO::TOptions::TVerifyCert>& verifyCert); + const TMaybe<TOpenSslClientIO::TOptions::TVerifyCert>& verifyCert, + bool keepAlive = true); bool IsOk() const { return IsNotSocketClosedByOtherSide(Socket); diff --git a/library/cpp/http/simple/http_client_options.h b/library/cpp/http/simple/http_client_options.h index 58849556a91..f237a3770a9 100644 --- a/library/cpp/http/simple/http_client_options.h +++ b/library/cpp/http/simple/http_client_options.h @@ -61,10 +61,30 @@ public: return MaxRedirectCount_; } + TSelf& UseKeepAlive(bool useKeepAlive) { + UseKeepAlive_ = useKeepAlive; + return *this; + } + + bool UseKeepAlive() const noexcept { + return UseKeepAlive_; + } + + TSelf& UseConnectionPool(bool useConnectionPool) { + UseConnectionPool_ = useConnectionPool; + return *this; + } + + bool UseConnectionPool() const noexcept { + return UseConnectionPool_; + } + private: TString Host_; ui16 Port_; TDuration SocketTimeout_ = TDuration::Seconds(5); TDuration ConnectTimeout_ = TDuration::Seconds(30); int MaxRedirectCount_ = INT_MAX; + bool UseKeepAlive_ = true; + bool UseConnectionPool_ = false; }; diff --git a/library/cpp/http/simple/ya.make b/library/cpp/http/simple/ya.make index 6a4e5775a4d..c645fb38442 100644 --- a/library/cpp/http/simple/ya.make +++ b/library/cpp/http/simple/ya.make @@ -1,6 +1,7 @@ LIBRARY() PEERDIR( + library/cpp/cache library/cpp/http/io library/cpp/openssl/io library/cpp/string_utils/url |