blob: e340d34501a442130aca8fe8d9d80f5ab6906f68 [file] [log] [blame]
#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_