Sfoglia il codice sorgente

[C++] [userver] Bump userver commit, switch to SAX-serialization, tune postgres a bit (#8737)

itrofimow 1 anno fa
parent
commit
366cbcd234

+ 3 - 2
frameworks/C++/userver/userver-bare.dockerfile

@@ -1,4 +1,4 @@
-FROM ghcr.io/userver-framework/ubuntu-userver-build-base:v1 AS builder
+FROM ghcr.io/userver-framework/ubuntu-userver-build-base:v2 AS builder
 
 RUN apt update && \
     apt install -y lsb-release wget software-properties-common gnupg && \
@@ -6,7 +6,8 @@ RUN apt update && \
 
 WORKDIR /src
 RUN git clone https://github.com/userver-framework/userver.git && \
-    cd userver && git checkout b85d540d7022e344f6fcf9fd467c67b046c961fe
+    cd userver && git checkout fcf0514be560f46740f8a654f2fdce5dc1cd450c
+
 COPY userver_benchmark/ ./
 RUN mkdir build && cd build && \
     cmake -DUSERVER_IS_THE_ROOT_PROJECT=0 -DUSERVER_FEATURE_CRYPTOPP_BLAKE2=0 \

+ 3 - 2
frameworks/C++/userver/userver.dockerfile

@@ -1,4 +1,4 @@
-FROM ghcr.io/userver-framework/ubuntu-userver-build-base:v1 AS builder
+FROM ghcr.io/userver-framework/ubuntu-userver-build-base:v2 AS builder
 
 RUN apt update && \
     apt install -y lsb-release wget software-properties-common gnupg && \
@@ -6,7 +6,8 @@ RUN apt update && \
 
 WORKDIR /src
 RUN git clone https://github.com/userver-framework/userver.git && \
-    cd userver && git checkout b85d540d7022e344f6fcf9fd467c67b046c961fe
+    cd userver && git checkout fcf0514be560f46740f8a654f2fdce5dc1cd450c
+
 COPY userver_benchmark/ ./
 RUN mkdir build && cd build && \
     cmake -DUSERVER_IS_THE_ROOT_PROJECT=0 -DUSERVER_FEATURE_CRYPTOPP_BLAKE2=0 \

+ 6 - 7
frameworks/C++/userver/userver_benchmark/bare/simple_connection.cpp

@@ -79,19 +79,18 @@ class ResponseBuffers final {
       return;
     }
 
-    boost::container::small_vector<userver::engine::io::IoData,
-                                   kMaxResponses * 2>
-        iovec(Size() * 2);
+    boost::container::small_vector<struct ::iovec, kMaxResponses * 2> io_vector(
+        Size() * 2);
 
     std::size_t index = 0;
     std::size_t total_size = 0;
-    for (const auto& response : responses_) {
-      iovec[index++] = {response.headers.data(), response.headers.size()};
-      iovec[index++] = {response.body.data(), response.body.size()};
+    for (auto& response : responses_) {
+      io_vector[index++] = {response.headers.data(), response.headers.size()};
+      io_vector[index++] = {response.body.data(), response.body.size()};
       total_size += response.headers.size() + response.body.size();
     }
 
-    if (socket.SendAll(iovec.data(), iovec.size(), {}) != total_size) {
+    if (socket.SendAll(io_vector.data(), io_vector.size(), {}) != total_size) {
       throw std::runtime_error{"Socket closed by remote"};
     }
 

+ 5 - 5
frameworks/C++/userver/userver_benchmark/bare/simple_router.cpp

@@ -52,32 +52,32 @@ SimpleResponse SimpleRouter::RouteRequest(std::string_view url) const {
   }
 
   if (StartsWith(url, kJsonUrlPrefix)) {
-    return {ToString(json::Handler::GetResponse()), kContentTypeJson};
+    return {json::Handler::GetResponse(), kContentTypeJson};
   }
 
   if (StartsWith(url, kSingleQueryUrlPrefix)) {
-    return {ToString(single_query_.GetResponse()), kContentTypeJson};
+    return {single_query_.GetResponse(), kContentTypeJson};
   }
 
   if (StartsWith(url, kMultipleQueriesUrlPrefix)) {
     const auto queries = db_helpers::ParseParamFromQuery(
         url.substr(kMultipleQueriesUrlPrefix.size()), "queries");
 
-    return {ToString(multiple_queries_.GetResponse(queries)), kContentTypeJson};
+    return {multiple_queries_.GetResponse(queries), kContentTypeJson};
   }
 
   if (StartsWith(url, kUpdatesUrlPrefix)) {
     const auto queries = db_helpers::ParseParamFromQuery(
         url.substr(kMultipleQueriesUrlPrefix.size()), "queries");
 
-    return {ToString(updates_.GetResponse(queries)), kContentTypeJson};
+    return {updates_.GetResponse(queries), kContentTypeJson};
   }
 
   if (StartsWith(url, kCachedQueriesUrlPrefix)) {
     const auto count = db_helpers::ParseParamFromQuery(
         url.substr(kCachedQueriesUrlPrefix.size()), "count");
 
-    return {ToString(cached_queries_.GetResponse(count)), kContentTypeJson};
+    return {cached_queries_.GetResponse(count), kContentTypeJson};
   }
 
   if (StartsWith(url, kFortunesUrlPrefix)) {

+ 12 - 9
frameworks/C++/userver/userver_benchmark/common/db_helpers.cpp

@@ -3,7 +3,6 @@
 #include <cctype>
 #include <charconv>
 
-#include <userver/formats/json/inline.hpp>
 #include <userver/utils/rand.hpp>
 
 namespace userver_techempower::db_helpers {
@@ -30,10 +29,21 @@ int ParseFromQueryVal(std::string_view query_val) {
 userver::storages::postgres::Query CreateNonLoggingQuery(
     std::string statement) {
   return userver::storages::postgres::Query{
-      statement, std::nullopt /* name */,
+      std::move(statement), std::nullopt /* name */,
       userver::storages::postgres::Query::LogMode::kNameOnly};
 }
 
+void WriteToStream(const WorldTableRow& row,
+                   userver::formats::json::StringBuilder& sb) {
+  userver::formats::json::StringBuilder::ObjectGuard obj{sb};
+
+  sb.Key("id");
+  WriteToStream(row.id, sb);
+
+  sb.Key("randomNumber");
+  WriteToStream(row.random_number, sb);
+}
+
 int GenerateRandomId() {
   return userver::utils::RandRange(1, kMaxWorldRows + 1);
 }
@@ -42,13 +52,6 @@ int GenerateRandomValue() {
   return userver::utils::RandRange(1, kMaxWorldRows + 1);
 }
 
-userver::formats::json::Value Serialize(
-    const WorldTableRow& value,
-    userver::formats::serialize::To<userver::formats::json::Value>) {
-  return userver::formats::json::MakeObject("id", value.id, "randomNumber",
-                                            value.random_number);
-}
-
 int ParseParamFromQuery(const userver::server::http::HttpRequest& request,
                         const std::string& name) {
   const auto& arg_str = request.GetArg(name);

+ 9 - 4
frameworks/C++/userver/userver_benchmark/common/db_helpers.hpp

@@ -1,9 +1,12 @@
 #pragma once
 
 #include <userver/engine/semaphore.hpp>
+#include <userver/formats/json/string_builder.hpp>
 #include <userver/formats/json/value.hpp>
+#include <userver/formats/serialize/write_to_stream.hpp>
 #include <userver/server/http/http_request.hpp>
 #include <userver/storages/postgres/cluster_types.hpp>
+#include <userver/storages/postgres/options.hpp>
 #include <userver/storages/postgres/query.hpp>
 
 namespace userver_techempower::db_helpers {
@@ -18,6 +21,9 @@ const userver::storages::postgres::Query kSelectRowQuery =
 constexpr auto kClusterHostType =
     userver::storages::postgres::ClusterHostType::kMaster;
 
+constexpr userver::storages::postgres::CommandControl kDefaultPgCC{
+    std::chrono::seconds{7}, std::chrono::seconds{7}};
+
 constexpr std::string_view kDbComponentName = "hello-world-db";
 
 struct WorldTableRow final {
@@ -25,13 +31,12 @@ struct WorldTableRow final {
   int random_number;
 };
 
+void WriteToStream(const WorldTableRow& row,
+                   userver::formats::json::StringBuilder& sb);
+
 int GenerateRandomId();
 int GenerateRandomValue();
 
-userver::formats::json::Value Serialize(
-    const WorldTableRow& value,
-    userver::formats::serialize::To<userver::formats::json::Value>);
-
 int ParseParamFromQuery(const userver::server::http::HttpRequest& request,
                         const std::string& name);
 

+ 11 - 7
frameworks/C++/userver/userver_benchmark/controllers/cached_queries/handler.cpp

@@ -1,28 +1,30 @@
 #include "handler.hpp"
 
-#include <userver/formats/serialize/common_containers.hpp>
-
 #include <boost/container/small_vector.hpp>
 
+#include <userver/formats/serialize/common_containers.hpp>
+#include <userver/http/common_headers.hpp>
+
 namespace userver_techempower::cached_queries {
 
 Handler::Handler(const userver::components::ComponentConfig& config,
                  const userver::components::ComponentContext& context)
-    : userver::server::handlers::HttpHandlerJsonBase{config, context},
+    : userver::server::handlers::HttpHandlerBase{config, context},
       cache_{context.FindComponent<WorldCacheComponent>()},
       query_arg_name_{"count"} {}
 
-userver::formats::json::Value Handler::HandleRequestJsonThrow(
+std::string Handler::HandleRequestThrow(
     const userver::server::http::HttpRequest& request,
-    const userver::formats::json::Value&,
     userver::server::request::RequestContext&) const {
   const auto queries =
       db_helpers::ParseParamFromQuery(request, query_arg_name_);
 
+  request.GetHttpResponse().SetHeader(userver::http::headers::kContentType,
+                                      "application/json");
   return GetResponse(queries);
 }
 
-userver::formats::json::Value Handler::GetResponse(int queries) const {
+std::string Handler::GetResponse(int queries) const {
   boost::container::small_vector<db_helpers::WorldTableRow, 500> result(
       queries);
 
@@ -31,7 +33,9 @@ userver::formats::json::Value Handler::GetResponse(int queries) const {
   std::generate(result.begin(), result.end(),
                 [&cache] { return cache.at(db_helpers::GenerateRandomId()); });
 
-  return userver::formats::json::ValueBuilder{result}.ExtractValue();
+  userver::formats::json::StringBuilder sb{};
+  WriteToStream(result, sb);
+  return sb.GetString();
 }
 
 }  // namespace userver_techempower::cached_queries

+ 4 - 5
frameworks/C++/userver/userver_benchmark/controllers/cached_queries/handler.hpp

@@ -1,24 +1,23 @@
 #pragma once
 
-#include <userver/server/handlers/http_handler_json_base.hpp>
+#include <userver/server/handlers/http_handler_base.hpp>
 
 #include "world_cache_component.hpp"
 
 namespace userver_techempower::cached_queries {
 
-class Handler final : public userver::server::handlers::HttpHandlerJsonBase {
+class Handler final : public userver::server::handlers::HttpHandlerBase {
  public:
   static constexpr std::string_view kName = "cached-queries-handler";
 
   Handler(const userver::components::ComponentConfig& config,
           const userver::components::ComponentContext& context);
 
-  userver::formats::json::Value HandleRequestJsonThrow(
+  std::string HandleRequestThrow(
       const userver::server::http::HttpRequest& request,
-      const userver::formats::json::Value&,
       userver::server::request::RequestContext&) const final;
 
-  userver::formats::json::Value GetResponse(int queries) const;
+  std::string GetResponse(int queries) const;
 
  private:
   const WorldCacheComponent& cache_;

+ 1 - 1
frameworks/C++/userver/userver_benchmark/controllers/fortunes/handler.cpp

@@ -147,7 +147,7 @@ std::string Handler::HandleRequestThrow(
 std::string Handler::GetResponse() const {
   const auto pg_result = [this] {
     const auto lock = semaphore_.Acquire();
-    return pg_->Execute(db_helpers::kClusterHostType,
+    return pg_->Execute(db_helpers::kClusterHostType, db_helpers::kDefaultPgCC,
                         select_all_fortunes_query_);
   }();
 

+ 14 - 5
frameworks/C++/userver/userver_benchmark/controllers/json/handler.cpp

@@ -1,16 +1,25 @@
 #include "handler.hpp"
 
+#include <userver/formats/json/string_builder.hpp>
+#include <userver/http/common_headers.hpp>
+
 namespace userver_techempower::json {
 
-userver::formats::json::Value Handler::HandleRequestJsonThrow(
-    const userver::server::http::HttpRequest&,
-    const userver::formats::json::Value&,
+std::string Handler::HandleRequestThrow(
+    const userver::server::http::HttpRequest& request,
     userver::server::request::RequestContext&) const {
+  request.GetHttpResponse().SetHeader(userver::http::headers::kContentType,
+                                      "application/json");
   return GetResponse();
 }
 
-userver::formats::json::Value Handler::GetResponse() {
-  return userver::formats::json::MakeObject("message", "Hello, World!");
+std::string Handler::GetResponse() {
+  const auto json =
+      userver::formats::json::MakeObject("message", "Hello, World!");
+
+  userver::formats::json::StringBuilder sb{};
+  sb.WriteValue(json);
+  return sb.GetString();
 }
 
 }  // namespace userver_techempower::json

+ 5 - 6
frameworks/C++/userver/userver_benchmark/controllers/json/handler.hpp

@@ -1,21 +1,20 @@
 #pragma once
 
-#include <userver/server/handlers/http_handler_json_base.hpp>
+#include <userver/server/handlers/http_handler_base.hpp>
 
 namespace userver_techempower::json {
 
-class Handler final : public userver::server::handlers::HttpHandlerJsonBase {
+class Handler final : public userver::server::handlers::HttpHandlerBase {
  public:
   static constexpr std::string_view kName = "json-handler";
 
-  using HttpHandlerJsonBase::HttpHandlerJsonBase;
+  using HttpHandlerBase::HttpHandlerBase;
 
-  userver::formats::json::Value HandleRequestJsonThrow(
+  std::string HandleRequestThrow(
       const userver::server::http::HttpRequest&,
-      const userver::formats::json::Value&,
       userver::server::request::RequestContext&) const final;
 
-  static userver::formats::json::Value GetResponse();
+  static std::string GetResponse();
 };
 
 }  // namespace userver_techempower::json

+ 13 - 7
frameworks/C++/userver/userver_benchmark/controllers/multiple_queries/handler.cpp

@@ -2,6 +2,7 @@
 
 #include <userver/components/component_context.hpp>
 #include <userver/formats/serialize/common_containers.hpp>
+#include <userver/http/common_headers.hpp>
 #include <userver/storages/postgres/postgres.hpp>
 
 #include <boost/container/small_vector.hpp>
@@ -16,7 +17,7 @@ constexpr std::size_t kBestConcurrencyWildGuess = 256;
 
 Handler::Handler(const userver::components::ComponentConfig& config,
                  const userver::components::ComponentContext& context)
-    : userver::server::handlers::HttpHandlerJsonBase{config, context},
+    : userver::server::handlers::HttpHandlerBase{config, context},
       pg_{context
               .FindComponent<userver::components::Postgres>(
                   db_helpers::kDbComponentName)
@@ -24,17 +25,18 @@ Handler::Handler(const userver::components::ComponentConfig& config,
       query_arg_name_{"queries"},
       semaphore_{kBestConcurrencyWildGuess} {}
 
-userver::formats::json::Value Handler::HandleRequestJsonThrow(
+std::string Handler::HandleRequestThrow(
     const userver::server::http::HttpRequest& request,
-    const userver::formats::json::Value&,
     userver::server::request::RequestContext&) const {
   const auto queries =
       db_helpers::ParseParamFromQuery(request, query_arg_name_);
 
+  request.GetHttpResponse().SetHeader(userver::http::headers::kContentType,
+                                      "application/json");
   return GetResponse(queries);
 }
 
-userver::formats::json::Value Handler::GetResponse(int queries) const {
+std::string Handler::GetResponse(int queries) const {
   boost::container::small_vector<db_helpers::WorldTableRow, 20> result(queries);
   for (auto& value : result) {
     value.id = db_helpers::GenerateRandomId();
@@ -43,9 +45,11 @@ userver::formats::json::Value Handler::GetResponse(int queries) const {
   {
     const auto lock = semaphore_.Acquire();
 
-    auto trx = pg_->Begin(db_helpers::kClusterHostType, {});
+    auto trx =
+        pg_->Begin(db_helpers::kClusterHostType, {}, db_helpers::kDefaultPgCC);
     for (auto& value : result) {
-      value.random_number = trx.Execute(db_helpers::kSelectRowQuery, value.id)
+      value.random_number = trx.Execute(db_helpers::kDefaultPgCC,
+                                        db_helpers::kSelectRowQuery, value.id)
                                 .AsSingleRow<db_helpers::WorldTableRow>(
                                     userver::storages::postgres::kRowTag)
                                 .random_number;
@@ -53,7 +57,9 @@ userver::formats::json::Value Handler::GetResponse(int queries) const {
     trx.Commit();
   }
 
-  return userver::formats::json::ValueBuilder{result}.ExtractValue();
+  userver::formats::json::StringBuilder sb{};
+  WriteToStream(result, sb);
+  return sb.GetString();
 }
 
 }  // namespace userver_techempower::multiple_queries

+ 4 - 5
frameworks/C++/userver/userver_benchmark/controllers/multiple_queries/handler.hpp

@@ -2,24 +2,23 @@
 
 #include "../../common/db_helpers.hpp"
 
-#include <userver/server/handlers/http_handler_json_base.hpp>
+#include <userver/server/handlers/http_handler_base.hpp>
 #include <userver/storages/postgres/postgres_fwd.hpp>
 
 namespace userver_techempower::multiple_queries {
 
-class Handler final : public userver::server::handlers::HttpHandlerJsonBase {
+class Handler final : public userver::server::handlers::HttpHandlerBase {
  public:
   static constexpr std::string_view kName = "multiple-queries-handler";
 
   Handler(const userver::components::ComponentConfig& config,
           const userver::components::ComponentContext& context);
 
-  userver::formats::json::Value HandleRequestJsonThrow(
+  std::string HandleRequestThrow(
       const userver::server::http::HttpRequest& request,
-      const userver::formats::json::Value&,
       userver::server::request::RequestContext&) const final;
 
-  userver::formats::json::Value GetResponse(int queries) const;
+  std::string GetResponse(int queries) const;
 
  private:
   const userver::storages::postgres::ClusterPtr pg_;

+ 12 - 8
frameworks/C++/userver/userver_benchmark/controllers/single_query/handler.cpp

@@ -1,6 +1,7 @@
 #include "handler.hpp"
 
 #include <userver/components/component_context.hpp>
+#include <userver/http/common_headers.hpp>
 #include <userver/storages/postgres/postgres.hpp>
 
 namespace userver_techempower::single_query {
@@ -13,31 +14,34 @@ constexpr std::size_t kBestConcurrencyWildGuess = 256;
 
 Handler::Handler(const userver::components::ComponentConfig& config,
                  const userver::components::ComponentContext& context)
-    : userver::server::handlers::HttpHandlerJsonBase{config, context},
+    : userver::server::handlers::HttpHandlerBase{config, context},
       pg_{context
               .FindComponent<userver::components::Postgres>(
                   db_helpers::kDbComponentName)
               .GetCluster()},
       semaphore_{kBestConcurrencyWildGuess} {}
 
-userver::formats::json::Value Handler::HandleRequestJsonThrow(
-    const userver::server::http::HttpRequest&,
-    const userver::formats::json::Value&,
+std::string Handler::HandleRequestThrow(
+    const userver::server::http::HttpRequest& request,
     userver::server::request::RequestContext&) const {
+  request.GetHttpResponse().SetHeader(userver::http::headers::kContentType,
+                                      "application/json");
   return GetResponse();
 }
 
-userver::formats::json::Value Handler::GetResponse() const {
+std::string Handler::GetResponse() const {
   const auto row = [this] {
     const auto lock = semaphore_.Acquire();
     return pg_
-        ->Execute(db_helpers::kClusterHostType, db_helpers::kSelectRowQuery,
-                  db_helpers::GenerateRandomId())
+        ->Execute(db_helpers::kClusterHostType, db_helpers::kDefaultPgCC,
+                  db_helpers::kSelectRowQuery, db_helpers::GenerateRandomId())
         .AsSingleRow<db_helpers::WorldTableRow>(
             userver::storages::postgres::kRowTag);
   }();
 
-  return db_helpers::Serialize(row, {});
+  userver::formats::json::StringBuilder sb{};
+  WriteToStream(row, sb);
+  return sb.GetString();
 }
 
 }  // namespace userver_techempower::single_query

+ 4 - 5
frameworks/C++/userver/userver_benchmark/controllers/single_query/handler.hpp

@@ -2,25 +2,24 @@
 
 #include "../../common/db_helpers.hpp"
 
-#include <userver/server/handlers/http_handler_json_base.hpp>
+#include <userver/server/handlers/http_handler_base.hpp>
 
 #include <userver/storages/postgres/postgres_fwd.hpp>
 
 namespace userver_techempower::single_query {
 
-class Handler final : public userver::server::handlers::HttpHandlerJsonBase {
+class Handler final : public userver::server::handlers::HttpHandlerBase {
  public:
   static constexpr std::string_view kName = "single-query-handler";
 
   Handler(const userver::components::ComponentConfig& config,
           const userver::components::ComponentContext& context);
 
-  userver::formats::json::Value HandleRequestJsonThrow(
+  std::string HandleRequestThrow(
       const userver::server::http::HttpRequest&,
-      const userver::formats::json::Value&,
       userver::server::request::RequestContext&) const final;
 
-  userver::formats::json::Value GetResponse() const;
+  std::string GetResponse() const;
 
  private:
   const userver::storages::postgres::ClusterPtr pg_;

+ 15 - 8
frameworks/C++/userver/userver_benchmark/controllers/updates/handler.cpp

@@ -2,6 +2,7 @@
 
 #include <userver/components/component_context.hpp>
 #include <userver/formats/serialize/common_containers.hpp>
+#include <userver/http/common_headers.hpp>
 #include <userver/storages/postgres/postgres.hpp>
 
 #include <boost/container/small_vector.hpp>
@@ -26,24 +27,25 @@ constexpr std::size_t kBestConcurrencyWildGuess = 128;
 
 Handler::Handler(const userver::components::ComponentConfig& config,
                  const userver::components::ComponentContext& context)
-    : userver::server::handlers::HttpHandlerJsonBase{config, context},
+    : userver::server::handlers::HttpHandlerBase{config, context},
       pg_{context.FindComponent<userver::components::Postgres>("hello-world-db")
               .GetCluster()},
       query_arg_name_{"queries"},
       update_query_{db_helpers::CreateNonLoggingQuery(kUpdateQueryStr)},
       semaphore_{kBestConcurrencyWildGuess} {}
 
-userver::formats::json::Value Handler::HandleRequestJsonThrow(
+std::string Handler::HandleRequestThrow(
     const userver::server::http::HttpRequest& request,
-    const userver::formats::json::Value&,
     userver::server::request::RequestContext&) const {
   const auto queries =
       db_helpers::ParseParamFromQuery(request, query_arg_name_);
 
+  request.GetHttpResponse().SetHeader(userver::http::headers::kContentType,
+                                      "application/json");
   return GetResponse(queries);
 }
 
-userver::formats::json::Value Handler::GetResponse(int queries) const {
+std::string Handler::GetResponse(int queries) const {
   // userver's PG doesn't accept boost::small_vector as an input, sadly
   std::vector<db_helpers::WorldTableRow> values(queries);
   for (auto& value : values) {
@@ -58,9 +60,11 @@ userver::formats::json::Value Handler::GetResponse(int queries) const {
   {
     const auto lock = semaphore_.Acquire();
 
-    auto trx = pg_->Begin(db_helpers::kClusterHostType, {});
+    auto trx =
+        pg_->Begin(db_helpers::kClusterHostType, {}, db_helpers::kDefaultPgCC);
     for (auto& value : values) {
-      value.random_number = trx.Execute(db_helpers::kSelectRowQuery, value.id)
+      value.random_number = trx.Execute(db_helpers::kDefaultPgCC,
+                                        db_helpers::kSelectRowQuery, value.id)
                                 .AsSingleRow<db_helpers::WorldTableRow>(
                                     userver::storages::postgres::kRowTag)
                                 .random_number;
@@ -74,11 +78,14 @@ userver::formats::json::Value Handler::GetResponse(int queries) const {
       value.random_number = db_helpers::GenerateRandomValue();
     }
 
-    trx.ExecuteDecomposeBulk(update_query_, values, values.size());
+    trx.ExecuteDecomposeBulk(db_helpers::kDefaultPgCC, update_query_, values,
+                             values.size());
     trx.Commit();
   }
 
-  return userver::formats::json::ValueBuilder{values}.ExtractValue();
+  userver::formats::json::StringBuilder sb{};
+  WriteToStream(result, sb);
+  return sb.GetString();
 }
 
 }  // namespace userver_techempower::updates

+ 4 - 5
frameworks/C++/userver/userver_benchmark/controllers/updates/handler.hpp

@@ -2,25 +2,24 @@
 
 #include "../../common/db_helpers.hpp"
 
-#include <userver/server/handlers/http_handler_json_base.hpp>
+#include <userver/server/handlers/http_handler_base.hpp>
 #include <userver/storages/postgres/postgres_fwd.hpp>
 #include <userver/storages/postgres/query.hpp>
 
 namespace userver_techempower::updates {
 
-class Handler final : public userver::server::handlers::HttpHandlerJsonBase {
+class Handler final : public userver::server::handlers::HttpHandlerBase {
  public:
   static constexpr std::string_view kName = "updates-handler";
 
   Handler(const userver::components::ComponentConfig& config,
           const userver::components::ComponentContext& context);
 
-  userver::formats::json::Value HandleRequestJsonThrow(
+  std::string HandleRequestThrow(
       const userver::server::http::HttpRequest& request,
-      const userver::formats::json::Value&,
       userver::server::request::RequestContext&) const final;
 
-  userver::formats::json::Value GetResponse(int queries) const;
+  std::string GetResponse(int queries) const;
 
  private:
   const userver::storages::postgres::ClusterPtr pg_;