feat: Cache state endpoint (#2642)

This commit is contained in:
Alex Kremer
2025-09-18 16:20:17 +01:00
committed by GitHub
parent 586a2116a4
commit 245a808e4b
9 changed files with 221 additions and 25 deletions

View File

@@ -189,6 +189,7 @@ ClioApplication::run(bool const useNgWebServer)
httpServer->onGet("/metrics", MetricsHandler{adminVerifier});
httpServer->onGet("/health", HealthCheckHandler{});
httpServer->onGet("/cache_state", CacheStateHandler{cache});
auto requestHandler = RequestHandler{adminVerifier, handler};
httpServer->onPost("/", requestHandler);
httpServer->onWs(std::move(requestHandler));
@@ -214,7 +215,7 @@ ClioApplication::run(bool const useNgWebServer)
// Init the web server
auto handler = std::make_shared<web::RPCServerHandler<RPCEngineType>>(config_, backend, rpcEngine, etl, dosGuard);
auto const httpServer = web::makeHttpServer(config_, ioc, dosGuard, handler);
auto const httpServer = web::makeHttpServer(config_, ioc, dosGuard, handler, cache);
// Blocks until stopped.
// When stopped, shared_ptrs fall out of scope

View File

@@ -120,4 +120,34 @@ HealthCheckHandler::operator()(
return web::ng::Response{boost::beast::http::status::ok, kHEALTH_CHECK_HTML, request};
}
web::ng::Response
CacheStateHandler::operator()(
web::ng::Request const& request,
web::ng::ConnectionMetadata&,
web::SubscriptionContextPtr,
boost::asio::yield_context
)
{
static constexpr auto kCACHE_CHECK_LOADED_HTML = R"html(
<!DOCTYPE html>
<html>
<head><title>Cache state</title></head>
<body><h1>Cache state</h1><p>Cache is fully loaded</p></body>
</html>
)html";
static constexpr auto kCACHE_CHECK_NOT_LOADED_HTML = R"html(
<!DOCTYPE html>
<html>
<head><title>Cache state</title></head>
<body><h1>Cache state</h1><p>Cache is not yet loaded</p></body>
</html>
)html";
if (cache_.get().isFull())
return web::ng::Response{boost::beast::http::status::ok, kCACHE_CHECK_LOADED_HTML, request};
return web::ng::Response{boost::beast::http::status::service_unavailable, kCACHE_CHECK_NOT_LOADED_HTML, request};
}
} // namespace app

View File

@@ -19,6 +19,7 @@
#pragma once
#include "data/LedgerCacheInterface.hpp"
#include "rpc/Errors.hpp"
#include "util/log/Logger.hpp"
#include "web/AdminVerificationStrategy.hpp"
@@ -163,6 +164,37 @@ public:
);
};
/**
* @brief A function object that handles the cache state check endpoint.
*/
class CacheStateHandler {
std::reference_wrapper<data::LedgerCacheInterface const> cache_;
public:
/**
* @brief Construct a new CacheStateHandler object.
*
* @param cache The ledger cache to use.
*/
CacheStateHandler(data::LedgerCacheInterface const& cache) : cache_{cache}
{
}
/**
* @brief The call of the function object.
*
* @param request The request to handle.
* @return The response to the request
*/
web::ng::Response
operator()(
web::ng::Request const& request,
web::ng::ConnectionMetadata&,
web::SubscriptionContextPtr,
boost::asio::yield_context
);
};
/**
* @brief A function object that handles the websocket endpoint.
*

View File

@@ -19,6 +19,7 @@
#pragma once
#include "data/LedgerCacheInterface.hpp"
#include "util/Taggable.hpp"
#include "web/AdminVerificationStrategy.hpp"
#include "web/PlainWsSession.hpp"
@@ -69,6 +70,7 @@ public:
* @param tagFactory A factory that is used to generate tags to track requests and sessions
* @param dosGuard The denial of service guard to use
* @param handler The server handler to use
* @param cache The ledger cache to use
* @param buffer Buffer with initial data received from the peer
* @param maxWsSendingQueueSize The maximum size of the sending queue for websocket
*/
@@ -80,6 +82,7 @@ public:
std::reference_wrapper<util::TagDecoratorFactory const> tagFactory,
std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard,
std::shared_ptr<HandlerType> const& handler,
std::reference_wrapper<data::LedgerCacheInterface const> cache,
boost::beast::flat_buffer buffer,
std::uint32_t maxWsSendingQueueSize
)
@@ -90,6 +93,7 @@ public:
std::move(proxyIpResolver),
dosGuard,
handler,
cache,
std::move(buffer)
)
, stream_(std::move(socket))

View File

@@ -19,6 +19,7 @@
#pragma once
#include "data/LedgerCacheInterface.hpp"
#include "util/Taggable.hpp"
#include "util/log/Logger.hpp"
#include "web/AdminVerificationStrategy.hpp"
@@ -85,6 +86,7 @@ class Detector : public std::enable_shared_from_this<Detector<PlainSessionType,
std::reference_wrapper<util::TagDecoratorFactory const> tagFactory_;
std::reference_wrapper<dosguard::DOSGuardInterface> const dosGuard_;
std::shared_ptr<HandlerType> const handler_;
std::reference_wrapper<data::LedgerCacheInterface const> cache_;
boost::beast::flat_buffer buffer_;
std::shared_ptr<AdminVerificationStrategy> const adminVerification_;
std::uint32_t maxWsSendingQueueSize_;
@@ -99,6 +101,7 @@ public:
* @param tagFactory A factory that is used to generate tags to track requests and sessions
* @param dosGuard The denial of service guard to use
* @param handler The server handler to use
* @param cache The ledger cache to use
* @param adminVerification The admin verification strategy to use
* @param maxWsSendingQueueSize The maximum size of the sending queue for websocket
* @param proxyIpResolver The client ip resolver if a request was forwarded by a proxy
@@ -109,6 +112,7 @@ public:
std::reference_wrapper<util::TagDecoratorFactory const> tagFactory,
std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard,
std::shared_ptr<HandlerType> handler,
std::reference_wrapper<data::LedgerCacheInterface const> cache,
std::shared_ptr<AdminVerificationStrategy> adminVerification,
std::uint32_t maxWsSendingQueueSize,
std::shared_ptr<ProxyIpResolver> proxyIpResolver
@@ -118,6 +122,7 @@ public:
, tagFactory_(std::cref(tagFactory))
, dosGuard_(dosGuard)
, handler_(std::move(handler))
, cache_(cache)
, adminVerification_(std::move(adminVerification))
, maxWsSendingQueueSize_(maxWsSendingQueueSize)
, proxyIpResolver_(std::move(proxyIpResolver))
@@ -179,6 +184,7 @@ public:
tagFactory_,
dosGuard_,
handler_,
cache_,
std::move(buffer_),
maxWsSendingQueueSize_
)
@@ -194,6 +200,7 @@ public:
tagFactory_,
dosGuard_,
handler_,
cache_,
std::move(buffer_),
maxWsSendingQueueSize_
)
@@ -223,6 +230,7 @@ class Server : public std::enable_shared_from_this<Server<PlainSessionType, SslS
util::TagDecoratorFactory tagFactory_;
std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard_;
std::shared_ptr<HandlerType> handler_;
std::reference_wrapper<data::LedgerCacheInterface const> cache_;
tcp::acceptor acceptor_;
std::shared_ptr<AdminVerificationStrategy> adminVerification_;
std::uint32_t maxWsSendingQueueSize_;
@@ -238,6 +246,7 @@ public:
* @param tagFactory A factory that is used to generate tags to track requests and sessions
* @param dosGuard The denial of service guard to use
* @param handler The server handler to use
* @param cache The ledger cache to use
* @param adminVerification The admin verification strategy to use
* @param maxWsSendingQueueSize The maximum size of the sending queue for websocket
* @param proxyIpResolver The client ip resolver if a request was forwarded by a proxy
@@ -249,6 +258,7 @@ public:
util::TagDecoratorFactory tagFactory,
dosguard::DOSGuardInterface& dosGuard,
std::shared_ptr<HandlerType> handler,
std::reference_wrapper<data::LedgerCacheInterface const> cache,
std::shared_ptr<AdminVerificationStrategy> adminVerification,
std::uint32_t maxWsSendingQueueSize,
ProxyIpResolver proxyIpResolver
@@ -258,6 +268,7 @@ public:
, tagFactory_(tagFactory)
, dosGuard_(std::ref(dosGuard))
, handler_(std::move(handler))
, cache_(cache)
, acceptor_(boost::asio::make_strand(ioc))
, adminVerification_(std::move(adminVerification))
, maxWsSendingQueueSize_(maxWsSendingQueueSize)
@@ -320,6 +331,7 @@ private:
std::cref(tagFactory_),
dosGuard_,
handler_,
cache_,
adminVerification_,
maxWsSendingQueueSize_,
proxyIpResolver_
@@ -343,6 +355,7 @@ using HttpServer = Server<HttpSession, SslHttpSession, HandlerType>;
* @param ioc The server will run under this io_context
* @param dosGuard The dos guard to protect the server
* @param handler The handler to process the request
* @param cache The ledger cache to use
* @return The server instance
*/
template <typename HandlerType>
@@ -351,7 +364,8 @@ makeHttpServer(
util::config::ClioConfigDefinition const& config,
boost::asio::io_context& ioc,
dosguard::DOSGuardInterface& dosGuard,
std::shared_ptr<HandlerType> const& handler
std::shared_ptr<HandlerType> const& handler,
std::reference_wrapper<data::LedgerCacheInterface const> cache
)
{
static util::Logger const log{"WebServer"}; // NOLINT(readability-identifier-naming)
@@ -385,6 +399,7 @@ makeHttpServer(
util::TagDecoratorFactory(config),
dosGuard,
handler,
cache,
std::move(expectedAdminVerification).value(),
maxWsSendingQueueSize,
std::move(proxyIpResolver)

View File

@@ -19,6 +19,7 @@
#pragma once
#include "data/LedgerCacheInterface.hpp"
#include "util/Taggable.hpp"
#include "web/AdminVerificationStrategy.hpp"
#include "web/ProxyIpResolver.hpp"
@@ -76,6 +77,7 @@ public:
* @param tagFactory A factory that is used to generate tags to track requests and sessions
* @param dosGuard The denial of service guard to use
* @param handler The server handler to use
* @param cache The ledger cache to use
* @param buffer Buffer with initial data received from the peer
* @param maxWsSendingQueueSize The maximum size of the sending queue for websocket
*/
@@ -88,6 +90,7 @@ public:
std::reference_wrapper<util::TagDecoratorFactory const> tagFactory,
std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard,
std::shared_ptr<HandlerType> const& handler,
std::reference_wrapper<data::LedgerCacheInterface const> cache,
boost::beast::flat_buffer buffer,
std::uint32_t maxWsSendingQueueSize
)
@@ -98,6 +101,7 @@ public:
std::move(proxyIpResolver),
dosGuard,
handler,
cache,
std::move(buffer)
)
, stream_(std::move(socket), ctx)

View File

@@ -19,6 +19,7 @@
#pragma once
#include "data/LedgerCacheInterface.hpp"
#include "rpc/Errors.hpp"
#include "util/Assert.hpp"
#include "util/Taggable.hpp"
@@ -71,6 +72,22 @@ static constexpr auto kHEALTH_CHECK_HTML = R"html(
</html>
)html";
static constexpr auto kCACHE_CHECK_LOADED_HTML = R"html(
<!DOCTYPE html>
<html>
<head><title>Cache state</title></head>
<body><h1>Cache state</h1><p>Cache is fully loaded</p></body>
</html>
)html";
static constexpr auto kCACHE_CHECK_NOT_LOADED_HTML = R"html(
<!DOCTYPE html>
<html>
<head><title>Cache state</title></head>
<body><h1>Cache state</h1><p>Cache is not yet loaded</p></body>
</html>
)html";
using tcp = boost::asio::ip::tcp;
/**
@@ -128,6 +145,7 @@ protected:
http::request<http::string_body> req_;
std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard_;
std::shared_ptr<HandlerType> const handler_;
std::reference_wrapper<data::LedgerCacheInterface const> cache_;
util::Logger log_{"WebServer"};
util::Logger perfLog_{"Performance"};
@@ -169,6 +187,7 @@ public:
std::shared_ptr<ProxyIpResolver> proxyIpResolver,
std::reference_wrapper<dosguard::DOSGuardInterface> dosGuard,
std::shared_ptr<HandlerType> handler,
std::reference_wrapper<data::LedgerCacheInterface const> cache,
boost::beast::flat_buffer buffer
)
: ConnectionBase(tagFactory, ip)
@@ -178,6 +197,7 @@ public:
, buffer_(std::move(buffer))
, dosGuard_(dosGuard)
, handler_(std::move(handler))
, cache_(cache)
{
LOG(perfLog_.debug()) << tag() << "http session created";
dosGuard_.get().increment(ip);
@@ -222,6 +242,13 @@ public:
if (req_.method() == http::verb::get and req_.target() == "/health")
return sender_(httpResponse(http::status::ok, "text/html", kHEALTH_CHECK_HTML));
if (req_.method() == http::verb::get and req_.target() == "/cache_state") {
if (cache_.get().isFull())
return sender_(httpResponse(http::status::ok, "text/html", kCACHE_CHECK_LOADED_HTML));
return sender_(httpResponse(http::status::service_unavailable, "text/html", kCACHE_CHECK_NOT_LOADED_HTML));
}
if (auto resolvedIp = proxyIpResolver_->resolveClientIp(clientIp_, req_); resolvedIp != clientIp_) {
LOG(log_.info()) << tag() << "Detected a forwarded request from proxy. Proxy ip: " << clientIp_
<< ". Resolved client ip: " << resolvedIp;