1919
2020#include " app/WebHandlers.hpp"
2121
22+ #include " rpc/Errors.hpp"
23+ #include " rpc/WorkQueue.hpp"
2224#include " util/Assert.hpp"
25+ #include " util/CoroutineGroup.hpp"
2326#include " util/prometheus/Http.hpp"
2427#include " web/AdminVerificationStrategy.hpp"
2528#include " web/SubscriptionContextInterface.hpp"
3134#include < boost/asio/spawn.hpp>
3235#include < boost/beast/http/status.hpp>
3336
37+ #include < functional>
3438#include < memory>
3539#include < optional>
3640#include < string>
@@ -76,8 +80,8 @@ DisconnectHook::operator()(web::ng::Connection const& connection)
7680 dosguard_.get ().decrement (connection.ip ());
7781}
7882
79- MetricsHandler::MetricsHandler (std::shared_ptr<web::AdminVerificationStrategy> adminVerifier)
80- : adminVerifier_{std::move (adminVerifier)}
83+ MetricsHandler::MetricsHandler (std::shared_ptr<web::AdminVerificationStrategy> adminVerifier, rpc::WorkQueue& workQueue )
84+ : adminVerifier_{std::move (adminVerifier)}, workQueue_{ std::ref (workQueue)}
8185{
8286}
8387
@@ -86,19 +90,45 @@ MetricsHandler::operator()(
8690 web::ng::Request const & request,
8791 web::ng::ConnectionMetadata& connectionMetadata,
8892 web::SubscriptionContextPtr,
89- boost::asio::yield_context
93+ boost::asio::yield_context yield
9094)
9195{
92- auto const maybeHttpRequest = request.asHttpRequest ();
93- ASSERT (maybeHttpRequest.has_value (), " Got not a http request in Get" );
94- auto const & httpRequest = maybeHttpRequest->get ();
95-
96- // FIXME(#1702): Using veb server thread to handle prometheus request. Better to post on work queue.
97- auto maybeResponse = util::prometheus::handlePrometheusRequest (
98- httpRequest, adminVerifier_->isAdmin (httpRequest, connectionMetadata.ip ())
96+ std::optional<web::ng::Response> response;
97+ util::CoroutineGroup coroutineGroup{yield, 1 };
98+ auto const onTaskComplete = coroutineGroup.registerForeign (yield);
99+ ASSERT (onTaskComplete.has_value (), " Coroutine group can't be full" );
100+
101+ bool const postSuccessful = workQueue_.get ().postCoro (
102+ [this , &request, &response, &onTaskComplete = onTaskComplete.value (), &connectionMetadata](
103+ boost::asio::yield_context
104+ ) mutable {
105+ auto const maybeHttpRequest = request.asHttpRequest ();
106+ ASSERT (maybeHttpRequest.has_value (), " Got not a http request in Get" );
107+ auto const & httpRequest = maybeHttpRequest->get ();
108+
109+ auto maybeResponse = util::prometheus::handlePrometheusRequest (
110+ httpRequest, adminVerifier_->isAdmin (httpRequest, connectionMetadata.ip ())
111+ );
112+ ASSERT (maybeResponse.has_value (), " Got unexpected request for Prometheus" );
113+ response = web::ng::Response{std::move (maybeResponse).value (), request};
114+ // notify the coroutine group that the foreign task is done
115+ onTaskComplete ();
116+ },
117+ /* isWhiteListed= */ true ,
118+ rpc::WorkQueue::Priority::High
99119 );
100- ASSERT (maybeResponse.has_value (), " Got unexpected request for Prometheus" );
101- return web::ng::Response{std::move (maybeResponse).value (), request};
120+
121+ if (!postSuccessful) {
122+ return web::ng::Response{
123+ boost::beast::http::status::too_many_requests, rpc::makeError (rpc::RippledError::rpcTOO_BUSY), request
124+ };
125+ }
126+
127+ // Put the coroutine to sleep until the foreign task is done
128+ coroutineGroup.asyncWait (yield);
129+ ASSERT (response.has_value (), " Woke up coroutine without setting response" );
130+
131+ return std::move (response).value ();
102132}
103133
104134web::ng::Response
0 commit comments