| #ifndef THIRD_PARTY_MILOTIC_INTERNAL_CC_PROXY_HTTP_CLIENT_POOL_H_ |
| #define THIRD_PARTY_MILOTIC_INTERNAL_CC_PROXY_HTTP_CLIENT_POOL_H_ |
| |
| #include <cstddef> |
| #include <memory> |
| #include <stack> |
| #include <utility> |
| |
| #include "absl/base/thread_annotations.h" |
| #include "absl/functional/any_invocable.h" |
| #include "absl/status/status.h" |
| #include "absl/status/statusor.h" |
| #include "absl/synchronization/mutex.h" |
| #include "absl/time/time.h" |
| #include "redfish_query_engine/http/client.h" |
| namespace milotic { |
| |
| // A pool of clients that can be used to send HTTP requests. |
| // |
| // The pool is initialized with a factory function that creates new clients |
| // on initialization. The pool maintains a stack of clients, and when a client |
| // is needed, the top of the stack is popped and returned. When a request is |
| // finished, the client is pushed back onto the stack. |
| // |
| // The pool can be configured with a maximum number of concurrent requests and a |
| // timeout for acquiring a client. If the maximum number of clients is already |
| // in use, subsequent requests will wait for a client to be available or |
| // timeout. |
| // |
| class HttpClientPool : public ecclesia::HttpClient { |
| public: |
| struct Config { |
| size_t max_concurrent_requests = 8; |
| absl::Duration acquire_client_timeout = absl::InfiniteDuration(); |
| }; |
| |
| explicit HttpClientPool( |
| absl::AnyInvocable<std::unique_ptr<ecclesia::HttpClient>()> |
| client_factory, |
| const Config& config); |
| |
| absl::StatusOr<HttpResponse> Get( |
| std::unique_ptr<HttpRequest> request) override { |
| return DoRequest(&ecclesia::HttpClient::Get, std::move(request)); |
| } |
| absl::StatusOr<HttpResponse> Post( |
| std::unique_ptr<HttpRequest> request) override { |
| return DoRequest(&ecclesia::HttpClient::Post, std::move(request)); |
| } |
| absl::StatusOr<HttpResponse> Delete( |
| std::unique_ptr<HttpRequest> request) override { |
| return DoRequest(&ecclesia::HttpClient::Delete, std::move(request)); |
| } |
| absl::StatusOr<HttpResponse> Patch( |
| std::unique_ptr<HttpRequest> request) override { |
| return DoRequest(&ecclesia::HttpClient::Patch, std::move(request)); |
| } |
| absl::Status GetIncremental(std::unique_ptr<HttpRequest> request, |
| IncrementalResponseHandler* handler) override { |
| return DoRequest(&ecclesia::HttpClient::GetIncremental, std::move(request), |
| handler); |
| } |
| absl::Status PostIncremental(std::unique_ptr<HttpRequest> request, |
| IncrementalResponseHandler* handler) override { |
| return DoRequest(&ecclesia::HttpClient::PostIncremental, std::move(request), |
| handler); |
| } |
| absl::Status DeleteIncremental(std::unique_ptr<HttpRequest> request, |
| IncrementalResponseHandler* handler) override { |
| return DoRequest(&ecclesia::HttpClient::DeleteIncremental, |
| std::move(request), handler); |
| } |
| absl::Status PatchIncremental(std::unique_ptr<HttpRequest> request, |
| IncrementalResponseHandler* handler) override { |
| return DoRequest(&ecclesia::HttpClient::PatchIncremental, |
| std::move(request), handler); |
| } |
| |
| private: |
| template <typename Result, typename... Args> |
| Result DoRequest(Result (ecclesia::HttpClient::*method)(Args...), |
| Args... args) { |
| std::unique_ptr<ecclesia::HttpClient> client = GetClient(); |
| if (client == nullptr) { |
| return absl::ResourceExhaustedError("No available clients"); |
| } |
| Result result = ((*client).*method)(std::forward<Args>(args)...); |
| ReturnClient(std::move(client)); |
| return result; |
| } |
| |
| std::unique_ptr<ecclesia::HttpClient> GetClient() ABSL_LOCKS_EXCLUDED(mutex_); |
| void ReturnClient(std::unique_ptr<ecclesia::HttpClient> client) |
| ABSL_LOCKS_EXCLUDED(mutex_); |
| |
| absl::Duration acquire_client_timeout_; |
| |
| absl::Mutex mutex_; |
| std::stack<std::unique_ptr<ecclesia::HttpClient>> clients_ |
| ABSL_GUARDED_BY(mutex_); |
| }; |
| |
| } // namespace milotic |
| |
| #endif // THIRD_PARTY_MILOTIC_INTERNAL_CC_PROXY_HTTP_CLIENT_POOL_H_ |