From 5962d49b18a1641f6a5c4f4bace7dabecf418dff Mon Sep 17 00:00:00 2001
From: kpavlov00 <kpavlov00@yandex-team.com>
Date: Thu, 23 Jan 2025 23:50:10 +0300
Subject: [PATCH] refactor grpc: ClientData clean up
 commit_hash:68737ed9ce03b32c0f093cea5ba3e97bd7552cac

---
 .mapping.json                                 | 10 ++-
 .../userver/ugrpc/client/client_factory.hpp   | 40 +---------
 .../ugrpc/client/client_factory_settings.hpp  |  6 +-
 .../userver/ugrpc/client/client_settings.hpp  | 58 ++++++++++++++
 .../{generic.hpp => generic_client.hpp}       |  2 +-
 .../ugrpc/client/impl/channel_factory.hpp     | 49 ++++++++++++
 .../userver/ugrpc/client/impl/client_data.hpp | 69 +++++++++--------
 .../client/impl/codegen_declarations.hpp      |  2 +-
 .../ugrpc/client/simple_client_component.hpp  |  2 +-
 ...tadata.hpp => static_service_metadata.hpp} | 13 ++++
 .../include/userver/ugrpc/impl/statistics.hpp |  2 +-
 .../ugrpc/server/impl/service_worker.hpp      |  2 +-
 .../ugrpc/server/impl/service_worker_impl.hpp | 10 +--
 grpc/src/ugrpc/client/client_factory.cpp      |  4 +-
 .../ugrpc/client/client_factory_settings.cpp  | 18 +++++
 grpc/src/ugrpc/client/client_settings.cpp     | 16 ++++
 .../{generic.cpp => generic_client.cpp}       |  2 +-
 grpc/src/ugrpc/client/impl/call_params.cpp    |  2 +-
 grpc/src/ugrpc/client/impl/client_data.cpp    | 77 ++++---------------
 .../ugrpc/client/simple_client_component.cpp  |  4 +-
 grpc/src/ugrpc/impl/statistics.cpp            |  2 +-
 grpc/tests/generic_client_test.cpp            |  2 +-
 samples/grpc-generic-proxy/main.cpp           |  2 +-
 .../grpc-generic-proxy/src/proxy_service.cpp  |  2 +-
 24 files changed, 235 insertions(+), 161 deletions(-)
 create mode 100644 grpc/include/userver/ugrpc/client/client_settings.hpp
 rename grpc/include/userver/ugrpc/client/{generic.hpp => generic_client.hpp} (98%)
 create mode 100644 grpc/include/userver/ugrpc/client/impl/channel_factory.hpp
 rename grpc/include/userver/ugrpc/impl/{static_metadata.hpp => static_service_metadata.hpp} (51%)
 create mode 100644 grpc/src/ugrpc/client/client_factory_settings.cpp
 create mode 100644 grpc/src/ugrpc/client/client_settings.cpp
 rename grpc/src/ugrpc/client/{generic.cpp => generic_client.cpp} (97%)

diff --git a/.mapping.json b/.mapping.json
index 6b8e21c88f23..676bdd5b5af3 100644
--- a/.mapping.json
+++ b/.mapping.json
@@ -1913,13 +1913,15 @@
   "grpc/include/userver/ugrpc/client/client_factory_component.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/client/client_factory_component.hpp",
   "grpc/include/userver/ugrpc/client/client_factory_settings.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/client/client_factory_settings.hpp",
   "grpc/include/userver/ugrpc/client/client_qos.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/client/client_qos.hpp",
+  "grpc/include/userver/ugrpc/client/client_settings.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/client/client_settings.hpp",
   "grpc/include/userver/ugrpc/client/common_component.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/client/common_component.hpp",
   "grpc/include/userver/ugrpc/client/exceptions.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/client/exceptions.hpp",
   "grpc/include/userver/ugrpc/client/fwd.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/client/fwd.hpp",
-  "grpc/include/userver/ugrpc/client/generic.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/client/generic.hpp",
+  "grpc/include/userver/ugrpc/client/generic_client.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/client/generic_client.hpp",
   "grpc/include/userver/ugrpc/client/impl/async_method_invocation.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/client/impl/async_method_invocation.hpp",
   "grpc/include/userver/ugrpc/client/impl/async_methods.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/client/impl/async_methods.hpp",
   "grpc/include/userver/ugrpc/client/impl/call_params.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/client/impl/call_params.hpp",
+  "grpc/include/userver/ugrpc/client/impl/channel_factory.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/client/impl/channel_factory.hpp",
   "grpc/include/userver/ugrpc/client/impl/client_data.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/client/impl/client_data.hpp",
   "grpc/include/userver/ugrpc/client/impl/codegen_declarations.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/client/impl/codegen_declarations.hpp",
   "grpc/include/userver/ugrpc/client/impl/codegen_definitions.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/client/impl/codegen_definitions.hpp",
@@ -1943,7 +1945,7 @@
   "grpc/include/userver/ugrpc/impl/protobuf_collector.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/impl/protobuf_collector.hpp",
   "grpc/include/userver/ugrpc/impl/queue_runner.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/impl/queue_runner.hpp",
   "grpc/include/userver/ugrpc/impl/span.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/impl/span.hpp",
-  "grpc/include/userver/ugrpc/impl/static_metadata.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/impl/static_metadata.hpp",
+  "grpc/include/userver/ugrpc/impl/static_service_metadata.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/impl/static_service_metadata.hpp",
   "grpc/include/userver/ugrpc/impl/statistics.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/impl/statistics.hpp",
   "grpc/include/userver/ugrpc/impl/statistics_scope.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/impl/statistics_scope.hpp",
   "grpc/include/userver/ugrpc/impl/statistics_storage.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/impl/statistics_storage.hpp",
@@ -2001,9 +2003,11 @@
   "grpc/src/ugrpc/client/channels.cpp":"taxi/uservices/userver/grpc/src/ugrpc/client/channels.cpp",
   "grpc/src/ugrpc/client/client_factory.cpp":"taxi/uservices/userver/grpc/src/ugrpc/client/client_factory.cpp",
   "grpc/src/ugrpc/client/client_factory_component.cpp":"taxi/uservices/userver/grpc/src/ugrpc/client/client_factory_component.cpp",
+  "grpc/src/ugrpc/client/client_factory_settings.cpp":"taxi/uservices/userver/grpc/src/ugrpc/client/client_factory_settings.cpp",
+  "grpc/src/ugrpc/client/client_settings.cpp":"taxi/uservices/userver/grpc/src/ugrpc/client/client_settings.cpp",
   "grpc/src/ugrpc/client/common_component.cpp":"taxi/uservices/userver/grpc/src/ugrpc/client/common_component.cpp",
   "grpc/src/ugrpc/client/exceptions.cpp":"taxi/uservices/userver/grpc/src/ugrpc/client/exceptions.cpp",
-  "grpc/src/ugrpc/client/generic.cpp":"taxi/uservices/userver/grpc/src/ugrpc/client/generic.cpp",
+  "grpc/src/ugrpc/client/generic_client.cpp":"taxi/uservices/userver/grpc/src/ugrpc/client/generic_client.cpp",
   "grpc/src/ugrpc/client/impl/async_method_invocation.cpp":"taxi/uservices/userver/grpc/src/ugrpc/client/impl/async_method_invocation.cpp",
   "grpc/src/ugrpc/client/impl/async_methods.cpp":"taxi/uservices/userver/grpc/src/ugrpc/client/impl/async_methods.cpp",
   "grpc/src/ugrpc/client/impl/call_params.cpp":"taxi/uservices/userver/grpc/src/ugrpc/client/impl/call_params.cpp",
diff --git a/grpc/include/userver/ugrpc/client/client_factory.hpp b/grpc/include/userver/ugrpc/client/client_factory.hpp
index 7eb6e6684c2b..9a5f77033f05 100644
--- a/grpc/include/userver/ugrpc/client/client_factory.hpp
+++ b/grpc/include/userver/ugrpc/client/client_factory.hpp
@@ -6,15 +6,12 @@
 #include <string>
 #include <utility>
 
-#include <grpcpp/completion_queue.h>
-#include <grpcpp/security/credentials.h>
-
 #include <userver/dynamic_config/source.hpp>
 #include <userver/engine/task/task_processor_fwd.hpp>
 #include <userver/testsuite/grpc_control.hpp>
 
 #include <userver/ugrpc/client/client_factory_settings.hpp>
-#include <userver/ugrpc/client/fwd.hpp>
+#include <userver/ugrpc/client/client_settings.hpp>
 #include <userver/ugrpc/client/middlewares/base.hpp>
 
 USERVER_NAMESPACE_BEGIN
@@ -26,39 +23,6 @@ class CompletionQueuePoolBase;
 
 namespace ugrpc::client {
 
-/// Settings relating to creation of a code-generated client
-struct ClientSettings final {
-    /// **(Required)**
-    /// The name of the client, for diagnostics, credentials and middlewares.
-    std::string client_name;
-
-    /// **(Required)**
-    /// The URI to connect to, e.g. `http://my.domain.com:8080`.
-    /// Should not include any HTTP path, just schema, domain name and port. Unix
-    /// sockets are also supported. For details, see:
-    /// https://grpc.github.io/grpc/cpp/md_doc_naming.html
-    std::string endpoint;
-
-    /// **(Optional)**
-    /// The name of the QOS
-    /// @ref scripts/docs/en/userver/dynamic_config.md "dynamic config"
-    /// that will be applied automatically to every RPC.
-    ///
-    /// Timeout from QOS config is ignored if:
-    ///
-    /// * an explicit `qos` parameter is specified at RPC creation, or
-    /// * deadline is specified in the `client_context` passed at RPC creation.
-    ///
-    /// ## Client QOS config definition sample
-    ///
-    /// @snippet grpc/tests/tests/unit_test_client_qos.hpp  qos config key
-    const dynamic_config::Key<ClientQos>* client_qos{nullptr};
-
-    /// **(Optional)**
-    /// Dedicated high-load methods that have separate channels
-    DedicatedMethodsConfig dedicated_methods_config{};
-};
-
 /// @ingroup userver_clients
 ///
 /// @brief Creates gRPC clients.
@@ -92,7 +56,7 @@ class ClientFactory final {
         ugrpc::impl::CompletionQueuePoolBase& completion_queues,
         ugrpc::impl::StatisticsStorage& statistics_storage,
         testsuite::GrpcControl& testsuite_grpc,
-        dynamic_config::Source source
+        dynamic_config::Source config_source
     );
     /// @endcond
 
diff --git a/grpc/include/userver/ugrpc/client/client_factory_settings.hpp b/grpc/include/userver/ugrpc/client/client_factory_settings.hpp
index 22f6a1987605..7f05222a301e 100644
--- a/grpc/include/userver/ugrpc/client/client_factory_settings.hpp
+++ b/grpc/include/userver/ugrpc/client/client_factory_settings.hpp
@@ -16,9 +16,6 @@ USERVER_NAMESPACE_BEGIN
 
 namespace ugrpc::client {
 
-// method name -> count of channels
-using DedicatedMethodsConfig = std::unordered_map<std::string, std::size_t>;
-
 /// Settings relating to the ClientFactory
 struct ClientFactorySettings final {
     /// gRPC channel credentials, none by default
@@ -41,6 +38,9 @@ struct ClientFactorySettings final {
     std::size_t channel_count{1};
 };
 
+std::shared_ptr<grpc::ChannelCredentials>
+GetClientCredentials(const ClientFactorySettings& client_factory_settings, const std::string& client_name);
+
 }  // namespace ugrpc::client
 
 USERVER_NAMESPACE_END
diff --git a/grpc/include/userver/ugrpc/client/client_settings.hpp b/grpc/include/userver/ugrpc/client/client_settings.hpp
new file mode 100644
index 000000000000..3e4913b0e16b
--- /dev/null
+++ b/grpc/include/userver/ugrpc/client/client_settings.hpp
@@ -0,0 +1,58 @@
+#pragma once
+
+/// @file userver/ugrpc/client/client_settings.hpp
+/// @brief @copybrief ugrpc::client::ClientSettings
+
+#include <cstddef>
+#include <string>
+#include <unordered_map>
+
+#include <userver/dynamic_config/snapshot.hpp>
+
+#include <userver/ugrpc/client/fwd.hpp>
+
+USERVER_NAMESPACE_BEGIN
+
+namespace ugrpc::client {
+
+// rpc method name -> count of channels
+using DedicatedMethodsConfig = std::unordered_map<std::string, std::size_t>;
+
+/// Settings relating to creation of a code-generated client
+struct ClientSettings final {
+    /// **(Required)**
+    /// The name of the client, for diagnostics, credentials and middlewares.
+    std::string client_name;
+
+    /// **(Required)**
+    /// The URI to connect to, e.g. `http://my.domain.com:8080`.
+    /// Should not include any HTTP path, just schema, domain name and port. Unix
+    /// sockets are also supported. For details, see:
+    /// https://grpc.github.io/grpc/cpp/md_doc_naming.html
+    std::string endpoint;
+
+    /// **(Optional)**
+    /// The name of the QOS
+    /// @ref scripts/docs/en/userver/dynamic_config.md "dynamic config"
+    /// that will be applied automatically to every RPC.
+    ///
+    /// Timeout from QOS config is ignored if:
+    ///
+    /// * an explicit `qos` parameter is specified at RPC creation, or
+    /// * deadline is specified in the `client_context` passed at RPC creation.
+    ///
+    /// ## Client QOS config definition sample
+    ///
+    /// @snippet grpc/tests/tests/unit_test_client_qos.hpp  qos config key
+    const dynamic_config::Key<ClientQos>* client_qos{nullptr};
+
+    /// **(Optional)**
+    /// Dedicated high-load methods that have separate channels
+    DedicatedMethodsConfig dedicated_methods_config{};
+};
+
+std::size_t GetMethodChannelCount(const DedicatedMethodsConfig& dedicated_methods_config, std::string_view method_name);
+
+}  // namespace ugrpc::client
+
+USERVER_NAMESPACE_END
diff --git a/grpc/include/userver/ugrpc/client/generic.hpp b/grpc/include/userver/ugrpc/client/generic_client.hpp
similarity index 98%
rename from grpc/include/userver/ugrpc/client/generic.hpp
rename to grpc/include/userver/ugrpc/client/generic_client.hpp
index d1d60432a832..310e55567374 100644
--- a/grpc/include/userver/ugrpc/client/generic.hpp
+++ b/grpc/include/userver/ugrpc/client/generic_client.hpp
@@ -1,6 +1,6 @@
 #pragma once
 
-/// @file userver/ugrpc/client/generic.hpp
+/// @file userver/ugrpc/client/generic_client.hpp
 /// @brief @copybrief ugrpc::client::GenericClient
 
 #include <optional>
diff --git a/grpc/include/userver/ugrpc/client/impl/channel_factory.hpp b/grpc/include/userver/ugrpc/client/impl/channel_factory.hpp
new file mode 100644
index 000000000000..4fe951e30aaa
--- /dev/null
+++ b/grpc/include/userver/ugrpc/client/impl/channel_factory.hpp
@@ -0,0 +1,49 @@
+#pragma once
+
+#include <grpcpp/channel.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/security/credentials.h>
+#include <grpcpp/support/channel_arguments.h>
+
+#include <userver/engine/async.hpp>
+
+#include <userver/ugrpc/impl/to_string.hpp>
+
+USERVER_NAMESPACE_BEGIN
+
+namespace ugrpc::client::impl {
+
+class ChannelFactory final {
+public:
+    ChannelFactory(
+        engine::TaskProcessor& blocking_task_processor,
+        const std::string& endpoint,
+        std::shared_ptr<grpc::ChannelCredentials> credentials,
+        const grpc::ChannelArguments& channel_args
+    )
+        : blocking_task_processor_(blocking_task_processor),
+          endpoint_{ugrpc::impl::ToGrpcString(endpoint)},
+          credentials_{std::move(credentials)},
+          channel_args_{channel_args} {}
+
+    std::shared_ptr<grpc::Channel> CreateChannel() const {
+        return engine::AsyncNoSpan(
+                   blocking_task_processor_,
+                   grpc::CreateCustomChannel,
+                   std::ref(endpoint_),
+                   std::ref(credentials_),
+                   std::ref(channel_args_)
+        )
+            .Get();
+    }
+
+private:
+    engine::TaskProcessor& blocking_task_processor_;
+    grpc::string endpoint_;
+    std::shared_ptr<grpc::ChannelCredentials> credentials_;
+    const grpc::ChannelArguments& channel_args_;
+};
+
+}  // namespace ugrpc::client::impl
+
+USERVER_NAMESPACE_END
diff --git a/grpc/include/userver/ugrpc/client/impl/client_data.hpp b/grpc/include/userver/ugrpc/client/impl/client_data.hpp
index 701a5503282c..e5630055ca62 100644
--- a/grpc/include/userver/ugrpc/client/impl/client_data.hpp
+++ b/grpc/include/userver/ugrpc/client/impl/client_data.hpp
@@ -5,9 +5,7 @@
 #include <optional>
 #include <utility>
 
-#include <grpcpp/channel.h>
 #include <grpcpp/completion_queue.h>
-#include <grpcpp/security/credentials.h>
 
 #include <userver/dynamic_config/source.hpp>
 #include <userver/engine/task/task_processor_fwd.hpp>
@@ -15,11 +13,12 @@
 #include <userver/utils/fixed_array.hpp>
 
 #include <userver/ugrpc/client/client_factory_settings.hpp>
+#include <userver/ugrpc/client/client_settings.hpp>
 #include <userver/ugrpc/client/fwd.hpp>
+#include <userver/ugrpc/client/impl/channel_factory.hpp>
 #include <userver/ugrpc/client/middlewares/fwd.hpp>
-#include <userver/ugrpc/impl/static_metadata.hpp>
+#include <userver/ugrpc/impl/static_service_metadata.hpp>
 #include <userver/ugrpc/impl/statistics.hpp>
-#include <userver/ugrpc/impl/to_string.hpp>
 
 USERVER_NAMESPACE_BEGIN
 
@@ -28,10 +27,6 @@ class StatisticsStorage;
 class CompletionQueuePoolBase;
 }  // namespace ugrpc::impl
 
-namespace ugrpc::client {
-struct ClientFactorySettings;
-}
-
 namespace ugrpc::client::impl {
 
 /// Contains all non-code-generated dependencies for creating a gRPC client
@@ -44,7 +39,7 @@ struct ClientDependencies final {
     const dynamic_config::Source config_source;
     testsuite::GrpcControl& testsuite_grpc;
     const dynamic_config::Key<ClientQos>* qos{nullptr};
-    const ClientFactorySettings& settings;
+    const ClientFactorySettings& client_factory_settings;
     engine::TaskProcessor& channel_task_processor;
     DedicatedMethodsConfig dedicated_methods_config;
 };
@@ -66,14 +61,18 @@ class ClientData final {
         : dependencies_(std::move(dependencies)),
           metadata_(metadata),
           service_statistics_(&GetServiceStatistics()),
-          channels_(CreateChannels(dependencies_)),
+          channel_factory_(CreateChannelFactory(dependencies_)),
+          channels_(CreateChannels(channel_factory_, dependencies_.client_factory_settings.channel_count)),
           stubs_(MakeStubs<Service>(channels_)),
-          dedicated_stubs_(MakeDedicatedStubs<Service>(dependencies_, metadata)) {}
+          dedicated_stubs_(
+              MakeDedicatedStubs<Service>(channel_factory_, *metadata_, dependencies_.dedicated_methods_config)
+          ) {}
 
     template <typename Service>
     ClientData(ClientDependencies&& dependencies, GenericClientTag, std::in_place_type_t<Service>)
         : dependencies_(std::move(dependencies)),
-          channels_(CreateChannels(dependencies_)),
+          channel_factory_(CreateChannelFactory(dependencies_)),
+          channels_(CreateChannels(channel_factory_, dependencies_.client_factory_settings.channel_count)),
           stubs_(MakeStubs<Service>(channels_)) {}
 
     ClientData(ClientData&&) noexcept = default;
@@ -118,16 +117,10 @@ class ClientData final {
     std::size_t GetDedicatedChannelCount(std::size_t method_id) const;
 
 private:
-    static std::shared_ptr<grpc::Channel>
-    CreateChannelImpl(const ClientDependencies& dependencies, const grpc::string& endpoint);
+    static ChannelFactory CreateChannelFactory(const ClientDependencies& dependencies);
 
-    static utils::FixedArray<std::shared_ptr<grpc::Channel>> CreateChannels(const ClientDependencies& dependencies);
-
-    static std::size_t GetDedicatedChannelCountImpl(
-        const ClientDependencies& dependencies,
-        std::size_t method_id,
-        const ugrpc::impl::StaticServiceMetadata& meta
-    );
+    static utils::FixedArray<std::shared_ptr<grpc::Channel>>
+    CreateChannels(const ChannelFactory& channel_factory, std::size_t channel_count);
 
     using StubDeleterType = void (*)(void*);
     using StubPtr = std::unique_ptr<void, StubDeleterType>;
@@ -140,26 +133,34 @@ class ClientData final {
     }
 
     template <typename Service>
-    static utils::FixedArray<StubPtr> MakeStubs(const utils::FixedArray<std::shared_ptr<grpc::Channel>>& channels) {
+    static StubPtr MakeStub(const std::shared_ptr<grpc::Channel>& channel) {
+        return StubPtr(Service::NewStub(channel).release(), &StubDeleter<Service>);
+    }
+
+    template <typename Service>
+    static StubPool MakeStubs(const utils::FixedArray<std::shared_ptr<grpc::Channel>>& channels) {
         return utils::GenerateFixedArray(channels.size(), [&](std::size_t index) {
-            return StubPtr(Service::NewStub(channels[index]).release(), &StubDeleter<Service>);
+            return MakeStub<Service>(channels[index]);
         });
     }
 
     template <typename Service>
-    static utils::FixedArray<StubPool>
-    MakeDedicatedStubs(const ClientDependencies& dependencies, const ugrpc::impl::StaticServiceMetadata& meta) {
-        const auto& method_full_names = meta.method_full_names;
-        const auto endpoint_string = ugrpc::impl::ToGrpcString(dependencies.endpoint);
-        return utils::GenerateFixedArray(method_full_names.size(), [&](std::size_t method_id) {
-            const auto dedicated_channel_count = GetDedicatedChannelCountImpl(dependencies, method_id, meta);
-            return utils::GenerateFixedArray(dedicated_channel_count, [&](std::size_t) {
-                return StubPtr(Service::NewStub(CreateChannelImpl(dependencies, endpoint_string)).release(), &StubDeleter<Service>);
+    static utils::FixedArray<StubPool> MakeDedicatedStubs(
+        const ChannelFactory& channel_factory,
+        const ugrpc::impl::StaticServiceMetadata& metadata,
+        const DedicatedMethodsConfig& dedicated_methods_config
+    ) {
+        return utils::GenerateFixedArray(GetMethodsCount(metadata), [&](std::size_t method_id) {
+            const auto method_channel_count =
+                GetMethodChannelCount(dedicated_methods_config, GetMethodName(metadata, method_id));
+            return utils::GenerateFixedArray(method_channel_count, [&](std::size_t) {
+                const auto channel = channel_factory.CreateChannel();
+                return MakeStub<Service>(channel);
             });
         });
     }
 
-    const StubPtr& NextStubPtr(const utils::FixedArray<StubPtr>& stubs) const;
+    const StubPtr& NextStubPtr(const StubPool& stubs) const;
 
     ugrpc::impl::ServiceStatistics& GetServiceStatistics();
 
@@ -167,9 +168,11 @@ class ClientData final {
     std::optional<ugrpc::impl::StaticServiceMetadata> metadata_{std::nullopt};
     ugrpc::impl::ServiceStatistics* service_statistics_{nullptr};
 
+    ChannelFactory channel_factory_;
+
     utils::FixedArray<std::shared_ptr<grpc::Channel>> channels_;
 
-    utils::FixedArray<StubPtr> stubs_;
+    StubPool stubs_;
     // method_id -> stub_pool
     utils::FixedArray<StubPool> dedicated_stubs_;
 };
diff --git a/grpc/include/userver/ugrpc/client/impl/codegen_declarations.hpp b/grpc/include/userver/ugrpc/client/impl/codegen_declarations.hpp
index 4a97629636a7..4b10faf8f76d 100644
--- a/grpc/include/userver/ugrpc/client/impl/codegen_declarations.hpp
+++ b/grpc/include/userver/ugrpc/client/impl/codegen_declarations.hpp
@@ -12,5 +12,5 @@
 #include <userver/ugrpc/client/qos.hpp>
 #include <userver/ugrpc/client/response_future.hpp>
 #include <userver/ugrpc/client/rpc.hpp>
-#include <userver/ugrpc/impl/static_metadata.hpp>
+#include <userver/ugrpc/impl/static_service_metadata.hpp>
 #include <userver/ugrpc/impl/statistics.hpp>
diff --git a/grpc/include/userver/ugrpc/client/simple_client_component.hpp b/grpc/include/userver/ugrpc/client/simple_client_component.hpp
index 118c091f59db..aaca1cf845fa 100644
--- a/grpc/include/userver/ugrpc/client/simple_client_component.hpp
+++ b/grpc/include/userver/ugrpc/client/simple_client_component.hpp
@@ -64,7 +64,7 @@ class SimpleClientComponentAny : public components::ComponentBase {
 /// ---- | ----------- | -------------
 /// endpoint | URL of the gRPC service | --
 /// client-name | name of the gRPC server we talk to, for diagnostics | <uses the component name>
-/// dedicated-channel-counts | a map of method names to channel counts. Used for high-load methods | -
+/// dedicated-channel-counts | a map of rpc method names to channel counts. Used for high-load methods | -
 /// factory-component | ClientFactoryComponent name to use for client creation | --
 
 // clang-format on
diff --git a/grpc/include/userver/ugrpc/impl/static_metadata.hpp b/grpc/include/userver/ugrpc/impl/static_service_metadata.hpp
similarity index 51%
rename from grpc/include/userver/ugrpc/impl/static_metadata.hpp
rename to grpc/include/userver/ugrpc/impl/static_service_metadata.hpp
index 3fb96b7c9906..98e1b1038370 100644
--- a/grpc/include/userver/ugrpc/impl/static_metadata.hpp
+++ b/grpc/include/userver/ugrpc/impl/static_service_metadata.hpp
@@ -20,6 +20,19 @@ constexpr StaticServiceMetadata MakeStaticServiceMetadata(utils::span<const std:
     return {GrpcppService::service_full_name(), method_full_names};
 }
 
+constexpr std::size_t GetMethodsCount(const StaticServiceMetadata& metadata) noexcept {
+    return metadata.method_full_names.size();
+}
+
+constexpr std::string_view GetMethodFullName(const StaticServiceMetadata& metadata, std::size_t method_id) {
+    return metadata.method_full_names[method_id];
+}
+
+constexpr std::string_view GetMethodName(const StaticServiceMetadata& metadata, std::size_t method_id) {
+    const auto& method_full_name = metadata.method_full_names[method_id];
+    return method_full_name.substr(metadata.service_full_name.size() + 1);
+}
+
 }  // namespace ugrpc::impl
 
 USERVER_NAMESPACE_END
diff --git a/grpc/include/userver/ugrpc/impl/statistics.hpp b/grpc/include/userver/ugrpc/impl/statistics.hpp
index 987b675e4f8d..6bc5b1826bf2 100644
--- a/grpc/include/userver/ugrpc/impl/statistics.hpp
+++ b/grpc/include/userver/ugrpc/impl/statistics.hpp
@@ -7,7 +7,7 @@
 #include <string_view>
 
 #include <userver/ugrpc/impl/code_statistics.hpp>
-#include <userver/ugrpc/impl/static_metadata.hpp>
+#include <userver/ugrpc/impl/static_service_metadata.hpp>
 
 #include <userver/utils/fixed_array.hpp>
 #include <userver/utils/statistics/fwd.hpp>
diff --git a/grpc/include/userver/ugrpc/server/impl/service_worker.hpp b/grpc/include/userver/ugrpc/server/impl/service_worker.hpp
index b2087f7993e6..62b0e75534b3 100644
--- a/grpc/include/userver/ugrpc/server/impl/service_worker.hpp
+++ b/grpc/include/userver/ugrpc/server/impl/service_worker.hpp
@@ -14,7 +14,7 @@
 #include <userver/utils/fixed_array.hpp>
 #include <userver/utils/statistics/fwd.hpp>
 
-#include <userver/ugrpc/impl/static_metadata.hpp>
+#include <userver/ugrpc/impl/static_service_metadata.hpp>
 #include <userver/ugrpc/impl/statistics_storage.hpp>
 #include <userver/ugrpc/server/impl/completion_queue_pool.hpp>
 #include <userver/ugrpc/server/middlewares/fwd.hpp>
diff --git a/grpc/include/userver/ugrpc/server/impl/service_worker_impl.hpp b/grpc/include/userver/ugrpc/server/impl/service_worker_impl.hpp
index c1bc94f776b0..ce42017aac52 100644
--- a/grpc/include/userver/ugrpc/server/impl/service_worker_impl.hpp
+++ b/grpc/include/userver/ugrpc/server/impl/service_worker_impl.hpp
@@ -22,7 +22,7 @@
 #include <userver/utils/lazy_prvalue.hpp>
 #include <userver/utils/statistics/entry.hpp>
 
-#include <userver/ugrpc/impl/static_metadata.hpp>
+#include <userver/ugrpc/impl/static_service_metadata.hpp>
 #include <userver/ugrpc/impl/statistics.hpp>
 #include <userver/ugrpc/impl/statistics_scope.hpp>
 #include <userver/ugrpc/server/call_context.hpp>
@@ -84,7 +84,7 @@ struct ServiceData final {
 
     const ServiceSettings settings;
     const ugrpc::impl::StaticServiceMetadata metadata;
-    AsyncService<GrpcppService> async_service{metadata.method_full_names.size()};
+    AsyncService<GrpcppService> async_service{GetMethodsCount(metadata)};
     utils::impl::WaitTokenStorage wait_tokens;
     ugrpc::impl::ServiceStatistics& service_statistics{
         settings.statistics_storage.GetServiceStatistics(metadata, std::nullopt)};
@@ -99,9 +99,9 @@ struct MethodData final {
     typename CallTraits::ServiceBase& service;
     const typename CallTraits::ServiceMethod service_method;
 
-    std::string_view call_name{service_data.metadata.method_full_names[method_id]};
+    std::string_view call_name{GetMethodFullName(service_data.metadata, method_id)};
     // Remove name of the service and slash
-    std::string_view method_name{call_name.substr(service_data.metadata.service_full_name.size() + 1)};
+    std::string_view method_name{GetMethodName(service_data.metadata, method_id)};
     ugrpc::impl::MethodStatistics& statistics{service_data.service_statistics.GetMethodStatistics(method_id)};
 };
 
@@ -110,7 +110,7 @@ class CallData final {
 public:
     explicit CallData(const MethodData<GrpcppService, CallTraits>& method_data)
         : wait_token_(method_data.service_data.wait_tokens.GetToken()), method_data_(method_data) {
-        UASSERT(method_data.method_id < method_data.service_data.metadata.method_full_names.size());
+        UASSERT(method_data.method_id < GetMethodsCount(method_data.service_data.metadata));
     }
 
     void operator()() && {
diff --git a/grpc/src/ugrpc/client/client_factory.cpp b/grpc/src/ugrpc/client/client_factory.cpp
index 62ae471c9cf7..2593163decea 100644
--- a/grpc/src/ugrpc/client/client_factory.cpp
+++ b/grpc/src/ugrpc/client/client_factory.cpp
@@ -13,14 +13,14 @@ ClientFactory::ClientFactory(
     ugrpc::impl::CompletionQueuePoolBase& completion_queues,
     ugrpc::impl::StatisticsStorage& statistics_storage,
     testsuite::GrpcControl& testsuite_grpc,
-    dynamic_config::Source source
+    dynamic_config::Source config_source
 )
     : settings_(std::move(settings)),
       channel_task_processor_(channel_task_processor),
       mws_(mws),
       completion_queues_(completion_queues),
       client_statistics_storage_(statistics_storage),
-      config_source_(source),
+      config_source_(config_source),
       testsuite_grpc_(testsuite_grpc) {
     ugrpc::impl::SetupNativeLogging();
     ugrpc::impl::UpdateNativeLogLevel(settings_.native_log_level);
diff --git a/grpc/src/ugrpc/client/client_factory_settings.cpp b/grpc/src/ugrpc/client/client_factory_settings.cpp
new file mode 100644
index 000000000000..cace149a3926
--- /dev/null
+++ b/grpc/src/ugrpc/client/client_factory_settings.cpp
@@ -0,0 +1,18 @@
+#include <userver/ugrpc/client/client_factory_settings.hpp>
+
+#include <userver/utils/algo.hpp>
+
+USERVER_NAMESPACE_BEGIN
+
+namespace ugrpc::client {
+
+std::shared_ptr<grpc::ChannelCredentials>
+GetClientCredentials(const ClientFactorySettings& client_factory_settings, const std::string& client_name) {
+    return utils::FindOrDefault(
+        client_factory_settings.client_credentials, client_name, client_factory_settings.credentials
+    );
+}
+
+}  // namespace ugrpc::client
+
+USERVER_NAMESPACE_END
diff --git a/grpc/src/ugrpc/client/client_settings.cpp b/grpc/src/ugrpc/client/client_settings.cpp
new file mode 100644
index 000000000000..0ac1f7b7ed4a
--- /dev/null
+++ b/grpc/src/ugrpc/client/client_settings.cpp
@@ -0,0 +1,16 @@
+#include <userver/ugrpc/client/client_settings.hpp>
+
+#include <userver/utils/algo.hpp>
+
+USERVER_NAMESPACE_BEGIN
+
+namespace ugrpc::client {
+
+std::size_t
+GetMethodChannelCount(const DedicatedMethodsConfig& dedicated_methods_config, std::string_view method_name) {
+    return utils::FindOrDefault(dedicated_methods_config, std::string{method_name}, std::size_t{0});
+}
+
+}  // namespace ugrpc::client
+
+USERVER_NAMESPACE_END
diff --git a/grpc/src/ugrpc/client/generic.cpp b/grpc/src/ugrpc/client/generic_client.cpp
similarity index 97%
rename from grpc/src/ugrpc/client/generic.cpp
rename to grpc/src/ugrpc/client/generic_client.cpp
index 7231478a6754..e99527906595 100644
--- a/grpc/src/ugrpc/client/generic.cpp
+++ b/grpc/src/ugrpc/client/generic_client.cpp
@@ -1,4 +1,4 @@
-#include <userver/ugrpc/client/generic.hpp>
+#include <userver/ugrpc/client/generic_client.hpp>
 
 #include <grpcpp/generic/generic_stub.h>
 
diff --git a/grpc/src/ugrpc/client/impl/call_params.cpp b/grpc/src/ugrpc/client/impl/call_params.cpp
index 248a7ea46cba..4cc2ea1d12be 100644
--- a/grpc/src/ugrpc/client/impl/call_params.cpp
+++ b/grpc/src/ugrpc/client/impl/call_params.cpp
@@ -82,7 +82,7 @@ CallParams CreateCallParams(
     const Qos& qos
 ) {
     const auto& metadata = client_data.GetMetadata();
-    const auto call_name = metadata.method_full_names[method_id];
+    const auto call_name = GetMethodFullName(metadata, method_id);
 
     if (engine::current_task::ShouldCancel()) {
         throw RpcCancelledError(call_name, "RPC construction");
diff --git a/grpc/src/ugrpc/client/impl/client_data.cpp b/grpc/src/ugrpc/client/impl/client_data.cpp
index eb0440afe177..056f2e100945 100644
--- a/grpc/src/ugrpc/client/impl/client_data.cpp
+++ b/grpc/src/ugrpc/client/impl/client_data.cpp
@@ -1,16 +1,9 @@
 #include <userver/ugrpc/client/impl/client_data.hpp>
 
-#include <fmt/format.h>
-#include <fmt/ranges.h>
-#include <grpcpp/create_channel.h>
-
-#include <userver/engine/async.hpp>
 #include <userver/utils/algo.hpp>
 #include <userver/utils/assert.hpp>
 #include <userver/utils/rand.hpp>
 
-#include <userver/ugrpc/client/client_factory.hpp>
-#include <userver/ugrpc/client/client_factory_settings.hpp>
 #include <userver/ugrpc/client/client_qos.hpp>
 #include <userver/ugrpc/client/impl/completion_queue_pool.hpp>
 #include <userver/ugrpc/impl/statistics_storage.hpp>
@@ -19,24 +12,6 @@ USERVER_NAMESPACE_BEGIN
 
 namespace ugrpc::client::impl {
 
-namespace {
-
-std::shared_ptr<grpc::ChannelCredentials> GetCredentails(const ClientDependencies& dependencies) {
-    return utils::FindOrDefault(
-        dependencies.settings.client_credentials, dependencies.client_name, dependencies.settings.credentials
-    );
-}
-
-bool MethodExists(const ugrpc::impl::StaticServiceMetadata& meta, std::string_view method_name) {
-    const auto& rpc_paths = meta.method_full_names;
-    return std::find_if(rpc_paths.begin(), rpc_paths.end(), [&method_name, &meta](const std::string_view full_path) {
-               const auto method = full_path.substr(meta.service_full_name.size() + 1);
-               return method == method_name;
-           }) != rpc_paths.end();
-}
-
-}  // namespace
-
 grpc::CompletionQueue& ClientData::NextQueue() const { return dependencies_.completion_queues.NextQueue(); }
 
 ugrpc::impl::MethodStatistics& ClientData::GetStatistics(std::size_t method_id) const {
@@ -55,7 +30,7 @@ const ugrpc::impl::StaticServiceMetadata& ClientData::GetMetadata() const {
 
 const dynamic_config::Key<ClientQos>* ClientData::GetClientQos() const { return dependencies_.qos; }
 
-const ClientData::StubPtr& ClientData::NextStubPtr(const utils::FixedArray<StubPtr>& stubs) const {
+const ClientData::StubPtr& ClientData::NextStubPtr(const StubPool& stubs) const {
     return stubs[utils::RandRange(stubs.size())];
 }
 
@@ -68,46 +43,20 @@ std::size_t ClientData::GetDedicatedChannelCount(std::size_t method_id) const {
     return dedicated_stubs_[method_id].size();
 }
 
-std::shared_ptr<grpc::Channel>
-ClientData::CreateChannelImpl(const ClientDependencies& dependencies, const grpc::string& endpoint) {
-    return engine::AsyncNoSpan(
-               dependencies.channel_task_processor,
-               grpc::CreateCustomChannel,
-               std::ref(endpoint),
-               dependencies.testsuite_grpc.IsTlsEnabled() ? GetCredentails(dependencies)
-                                                          : grpc::InsecureChannelCredentials(),
-               std::ref(dependencies.settings.channel_args)
-    )
-        .Get();
-}
-
-utils::FixedArray<std::shared_ptr<grpc::Channel>> ClientData::CreateChannels(const ClientDependencies& dependencies) {
-    const auto endpoint_string = ugrpc::impl::ToGrpcString(dependencies.endpoint);
-    return utils::GenerateFixedArray(dependencies.settings.channel_count, [&](std::size_t) {
-        return CreateChannelImpl(dependencies, endpoint_string);
-    });
+ChannelFactory ClientData::CreateChannelFactory(const ClientDependencies& dependencies) {
+    auto credentials = dependencies.testsuite_grpc.IsTlsEnabled()
+                           ? GetClientCredentials(dependencies.client_factory_settings, dependencies.client_name)
+                           : grpc::InsecureChannelCredentials();
+    return ChannelFactory{
+        dependencies.channel_task_processor,
+        dependencies.endpoint,
+        std::move(credentials),
+        dependencies.client_factory_settings.channel_args};
 }
 
-std::size_t ClientData::GetDedicatedChannelCountImpl(
-    const ClientDependencies& dependencies,
-    std::size_t method_id,
-    const ugrpc::impl::StaticServiceMetadata& meta
-) {
-    const auto& rpc_paths = meta.method_full_names;
-    const auto& rpc_path = rpc_paths[method_id];
-    const auto method_name = rpc_path.substr(meta.service_full_name.size() + 1);
-    UASSERT(!method_name.empty());
-
-    const auto& dedicated_methods_config = dependencies.dedicated_methods_config;
-    const auto it = dedicated_methods_config.find(std::string{method_name});
-    if (it != dedicated_methods_config.end()) {
-        return it->second;
-    }
-    UINVARIANT(
-        MethodExists(meta, method_name),
-        fmt::format("Unknown method {}. Available methods: [{}]", method_name, fmt::join(rpc_paths, ", "))
-    );
-    return 0;
+utils::FixedArray<std::shared_ptr<grpc::Channel>>
+ClientData::CreateChannels(const ChannelFactory& channel_factory, std::size_t channel_count) {
+    return utils::GenerateFixedArray(channel_count, [&](std::size_t) { return channel_factory.CreateChannel(); });
 }
 
 }  // namespace ugrpc::client::impl
diff --git a/grpc/src/ugrpc/client/simple_client_component.cpp b/grpc/src/ugrpc/client/simple_client_component.cpp
index 7188e1b4da79..7b9c6ab43036 100644
--- a/grpc/src/ugrpc/client/simple_client_component.cpp
+++ b/grpc/src/ugrpc/client/simple_client_component.cpp
@@ -27,11 +27,11 @@ additionalProperties: false
         description: ClientFactoryComponent name to use for client creation
     dedicated-channel-counts:
         type: object
-        description: a map of method names to channel counts. Used for high-load methods
+        description: a map of rpc method names to channel counts. Used for high-load methods
         defaultDescription: '{}'
         additionalProperties:
             type: integer
-            description: a full path to service method, must be a string or integer
+            description: number of channels for this method
             minimum: 1
         properties: {}
 )");
diff --git a/grpc/src/ugrpc/impl/statistics.cpp b/grpc/src/ugrpc/impl/statistics.cpp
index 0e2eee4f972e..6aca768c1c49 100644
--- a/grpc/src/ugrpc/impl/statistics.cpp
+++ b/grpc/src/ugrpc/impl/statistics.cpp
@@ -184,7 +184,7 @@ ServiceStatistics::ServiceStatistics(
     StatisticsDomain domain,
     utils::statistics::StripedRateCounter& global_started
 )
-    : metadata_(metadata), method_statistics_(metadata.method_full_names.size(), domain, global_started) {}
+    : metadata_(metadata), method_statistics_(GetMethodsCount(metadata), domain, global_started) {}
 
 MethodStatistics& ServiceStatistics::GetMethodStatistics(std::size_t method_id) {
     return method_statistics_[method_id];
diff --git a/grpc/tests/generic_client_test.cpp b/grpc/tests/generic_client_test.cpp
index ffb805b898be..20ce9bf239ec 100644
--- a/grpc/tests/generic_client_test.cpp
+++ b/grpc/tests/generic_client_test.cpp
@@ -1,4 +1,4 @@
-#include <userver/ugrpc/client/generic.hpp>
+#include <userver/ugrpc/client/generic_client.hpp>
 
 #include <cstdint>
 
diff --git a/samples/grpc-generic-proxy/main.cpp b/samples/grpc-generic-proxy/main.cpp
index 8e51855b1424..b744c99065b1 100644
--- a/samples/grpc-generic-proxy/main.cpp
+++ b/samples/grpc-generic-proxy/main.cpp
@@ -11,7 +11,7 @@
 #include <userver/testsuite/testsuite_support.hpp>
 #include <userver/ugrpc/client/client_factory_component.hpp>
 #include <userver/ugrpc/client/common_component.hpp>
-#include <userver/ugrpc/client/generic.hpp>
+#include <userver/ugrpc/client/generic_client.hpp>
 #include <userver/ugrpc/client/middlewares/deadline_propagation/component.hpp>
 #include <userver/ugrpc/client/middlewares/log/component.hpp>
 #include <userver/ugrpc/client/simple_client_component.hpp>
diff --git a/samples/grpc-generic-proxy/src/proxy_service.cpp b/samples/grpc-generic-proxy/src/proxy_service.cpp
index a3e4a8a48eb7..bb68bd8508e9 100644
--- a/samples/grpc-generic-proxy/src/proxy_service.cpp
+++ b/samples/grpc-generic-proxy/src/proxy_service.cpp
@@ -6,7 +6,7 @@
 
 #include <userver/components/component.hpp>
 #include <userver/ugrpc/byte_buffer_utils.hpp>
-#include <userver/ugrpc/client/generic.hpp>
+#include <userver/ugrpc/client/generic_client.hpp>
 #include <userver/ugrpc/client/simple_client_component.hpp>
 
 namespace samples {