This is an automated email from the ASF dual-hosted git repository.

cmcfarlen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/master by this push:
     new 624462f3a9 Expose JSON client timeout to CLI (#12323)
624462f3a9 is described below

commit 624462f3a94e85093dc2207d3db84cf9ad1db029
Author: Chris McFarlen <[email protected]>
AuthorDate: Wed Jul 2 09:44:31 2025 -0500

    Expose JSON client timeout to CLI (#12323)
    
    * Expose JSON client timeout to CLI
    
    * Make default timeout much larger
---
 include/shared/rpc/RPCClient.h      | 10 +++++-----
 src/traffic_ctl/CtrlCommands.cc     | 31 +++++++++++++++++++++++++------
 src/traffic_ctl/CtrlCommands.h      | 25 +++++++++++++++----------
 src/traffic_ctl/FileConfigCommand.h |  3 +--
 src/traffic_ctl/traffic_ctl.cc      |  4 +++-
 src/traffic_top/stats.h             |  3 ++-
 6 files changed, 51 insertions(+), 25 deletions(-)

diff --git a/include/shared/rpc/RPCClient.h b/include/shared/rpc/RPCClient.h
index 57c629f1aa..a9b9453543 100644
--- a/include/shared/rpc/RPCClient.h
+++ b/include/shared/rpc/RPCClient.h
@@ -21,7 +21,7 @@
 
 /// JSONRPC 2.0 RPC network client.
 
-#include <iostream>
+#include <chrono>
 #include <string_view>
 
 #include <yaml-cpp/yaml.h>
@@ -48,7 +48,7 @@ public:
   /// endode/decode you can just call @c invoke(JSONRPCRequest const &req).
   /// @throw runtime_error
   std::string
-  invoke(std::string_view req)
+  invoke(std::string_view req, std::chrono::milliseconds timeout_ms, int 
attempts)
   {
     std::string err_text; // for error messages.
     try {
@@ -56,7 +56,7 @@ public:
       if (!_client.is_closed()) {
         std::string resp;
         _client.send(req);
-        switch (_client.read_all(resp)) {
+        switch (_client.read_all(resp, timeout_ms, attempts)) {
         case IPCSocketClient::ReadStatus::NO_ERROR: {
           _client.disconnect();
           return resp;
@@ -98,13 +98,13 @@ public:
   /// @throw YAML::Exception
   template <typename Codec = yamlcpp_json_emitter>
   JSONRPCResponse
-  invoke(JSONRPCRequest const &req)
+  invoke(JSONRPCRequest const &req, std::chrono::milliseconds timeout_ms, int 
attempts)
   {
     static_assert(internal::has_decode<Codec>::value || 
internal::has_encode<Codec>::value,
                   "You need to implement encode/decode in your own codec 
impl.");
     // We should add a static_assert and make sure encode/decode are part of 
Codec type.
     auto const &reqStr = Codec::encode(req);
-    return Codec::decode(invoke(reqStr));
+    return Codec::decode(invoke(reqStr, timeout_ms, attempts));
   }
 
 private:
diff --git a/src/traffic_ctl/CtrlCommands.cc b/src/traffic_ctl/CtrlCommands.cc
index 31fb78cf82..17efd4439d 100644
--- a/src/traffic_ctl/CtrlCommands.cc
+++ b/src/traffic_ctl/CtrlCommands.cc
@@ -85,14 +85,14 @@ CtrlCommand::execute()
 }
 
 std::string
-RPCAccessor::invoke_rpc(std::string const &request)
+RPCAccessor::invoke_rpc(std::string const &request, std::chrono::milliseconds 
timeout_ms, int attempts)
 {
   if (_printer->print_rpc_message()) {
     std::string text;
     swoc::bwprint(text, "--> {}", request);
     _printer->write_debug(std::string_view{text});
   }
-  if (auto resp = _rpcClient.invoke(request); !resp.empty()) {
+  if (auto resp = _rpcClient.invoke(request, timeout_ms, attempts); 
!resp.empty()) {
     // all good.
     if (_printer->print_rpc_message()) {
       std::string text;
@@ -106,18 +106,19 @@ RPCAccessor::invoke_rpc(std::string const &request)
 }
 
 shared::rpc::JSONRPCResponse
-RPCAccessor::invoke_rpc(shared::rpc::ClientRequest const &request)
+RPCAccessor::invoke_rpc(shared::rpc::ClientRequest const &request, 
std::chrono::milliseconds timeout_ms, int attempts)
 {
   std::string encodedRequest = Codec::encode(request);
-  std::string resp           = invoke_rpc(encodedRequest);
+  std::string resp           = invoke_rpc(encodedRequest, timeout_ms, 
attempts);
   return Codec::decode(resp);
 }
 
 void
-RPCAccessor::invoke_rpc(shared::rpc::ClientRequest const &request, std::string 
&resp)
+RPCAccessor::invoke_rpc(shared::rpc::ClientRequest const &request, std::string 
&resp, std::chrono::milliseconds timeout_ms,
+                        int attempts)
 {
   std::string encodedRequest = Codec::encode(request);
-  resp                       = invoke_rpc(encodedRequest);
+  resp                       = invoke_rpc(encodedRequest, timeout_ms, 
attempts);
 }
 // 
-----------------------------------------------------------------------------------------------------------------------------------
 ConfigCommand::ConfigCommand(ts::Arguments *args) : RecordCommand(args)
@@ -166,6 +167,24 @@ RecordCommand::record_fetch(ts::ArgumentData argData, bool 
isRegex, RecordQueryT
   return invoke_rpc(request);
 }
 
+std::string
+CtrlCommand::invoke_rpc(std::string const &request)
+{
+  auto timeout  = 
std::chrono::milliseconds(std::stoi(get_parsed_arguments()->get("read-timeout").value()));
+  auto attempts = 
std::stoi(get_parsed_arguments()->get("read-attempts").value());
+
+  return RPCAccessor::invoke_rpc(request, timeout, attempts);
+}
+
+shared::rpc::JSONRPCResponse
+CtrlCommand::invoke_rpc(shared::rpc::ClientRequest const &request)
+{
+  auto timeout  = 
std::chrono::milliseconds(std::stoi(get_parsed_arguments()->get("read-timeout").value()));
+  auto attempts = 
std::stoi(get_parsed_arguments()->get("read-attempts").value());
+
+  return RPCAccessor::invoke_rpc(request, timeout, attempts);
+}
+
 void
 ConfigCommand::config_match()
 {
diff --git a/src/traffic_ctl/CtrlCommands.h b/src/traffic_ctl/CtrlCommands.h
index e20d70d8dd..cc3a6ad8fa 100644
--- a/src/traffic_ctl/CtrlCommands.h
+++ b/src/traffic_ctl/CtrlCommands.h
@@ -34,16 +34,17 @@ protected:
   /// @param request A string representation of the json/yaml request.
   /// @return a string with the json/yaml response.
   /// @note This function does print the raw string if requested by the 
"--format". No printer involved, standard output.
-  std::string invoke_rpc(std::string const &request);
+  std::string invoke_rpc(std::string const &request, std::chrono::milliseconds 
timeout_ms, int attempts);
 
   /// @brief Function that calls the rpc server. This function takes a json 
objects and uses the defined coded to convert them to a
   ///        string. This function will call invoke_rpc(string) overload.
   /// @param A Client request.
   /// @return A server response.
-  shared::rpc::JSONRPCResponse invoke_rpc(shared::rpc::ClientRequest const 
&request);
+  shared::rpc::JSONRPCResponse invoke_rpc(shared::rpc::ClientRequest const 
&request, std::chrono::milliseconds timeout_ms,
+                                          int attempts);
 
   /// @brief Function that calls the rpc server. The response will not be 
decoded, it will be a raw string.
-  void invoke_rpc(shared::rpc::ClientRequest const &request, std::string &bw);
+  void invoke_rpc(shared::rpc::ClientRequest const &request, std::string &bw, 
std::chrono::milliseconds timeout_ms, int attempts);
 
   std::unique_ptr<BasePrinter> _printer; //!< Specific output formatter. This 
should be created by the derived class.
 private:
@@ -56,7 +57,7 @@ private:
 /// This class should be used as a base class for every new command or group 
of commands that are related.
 /// The base class will provide the client communication through the @c 
invoke_call member function. Arguments that were
 /// parsed by the traffic_ctl are available as a member to all the derived 
classes.
-class CtrlCommand
+class CtrlCommand : public RPCAccessor
 {
 public:
   virtual ~CtrlCommand() = default;
@@ -76,6 +77,10 @@ public:
   ///        should be set when the signal is handled.
   static std::atomic_int Signal_Flagged;
 
+  std::string invoke_rpc(std::string const &request);
+
+  shared::rpc::JSONRPCResponse invoke_rpc(shared::rpc::ClientRequest const 
&request);
+
 protected:
   /// @brief The whole design is that the command will execute the @c 
_invoked_func once invoked. This function ptr should be
   ///        set by the appropriated derived class base on the passed 
parameters. The derived class have the option to override
@@ -98,7 +103,7 @@ private:
 /// @brief Record Command Implementation
 ///        Used as base class for any command that needs to access to a TS 
record.
 ///        If deriving from this class, make sure you implement @c 
execute_subcommand() and call the _invoked_func yourself.
-class RecordCommand : public CtrlCommand, public RPCAccessor
+class RecordCommand : public CtrlCommand
 {
 public:
   using CtrlCommand::CtrlCommand;
@@ -157,7 +162,7 @@ public:
   MetricCommand(ts::Arguments *args);
 };
 // 
-----------------------------------------------------------------------------------------------------------------------------------
-class HostCommand : public CtrlCommand, public RPCAccessor
+class HostCommand : public CtrlCommand
 {
 public:
   HostCommand(ts::Arguments *args);
@@ -173,7 +178,7 @@ private:
   void status_up();
 };
 // 
-----------------------------------------------------------------------------------------------------------------------------------
-class PluginCommand : public CtrlCommand, public RPCAccessor
+class PluginCommand : public CtrlCommand
 {
 public:
   PluginCommand(ts::Arguments *args);
@@ -183,7 +188,7 @@ private:
   void                            plugin_msg();
 };
 // 
-----------------------------------------------------------------------------------------------------------------------------------
-class DirectRPCCommand : public CtrlCommand, public RPCAccessor
+class DirectRPCCommand : public CtrlCommand
 {
 public:
   DirectRPCCommand(ts::Arguments *args);
@@ -204,7 +209,7 @@ private:
   bool validate_input(std::string const &in) const;
 };
 // 
-----------------------------------------------------------------------------------------------------------------------------------
-class ServerCommand : public CtrlCommand, public RPCAccessor
+class ServerCommand : public CtrlCommand
 {
 public:
   ServerCommand(ts::Arguments *args);
@@ -228,7 +233,7 @@ private:
 };
 //
 // 
-----------------------------------------------------------------------------------------------------------------------------------
-struct StorageCommand : public CtrlCommand, public RPCAccessor {
+struct StorageCommand : public CtrlCommand {
   StorageCommand(ts::Arguments *args);
 
 private:
diff --git a/src/traffic_ctl/FileConfigCommand.h 
b/src/traffic_ctl/FileConfigCommand.h
index 9f4c3bb03c..e1eab75293 100644
--- a/src/traffic_ctl/FileConfigCommand.h
+++ b/src/traffic_ctl/FileConfigCommand.h
@@ -67,8 +67,7 @@ struct FlatYAMLAccessor {
   }
 
 protected:
-  std::vector<YAML::Node>      _docs;
-  std::unique_ptr<BasePrinter> _printer; //!< Specific output formatter. This 
should be created by the derived class.
+  std::vector<YAML::Node> _docs;
 };
 
 /// @brief Class used to deal with the config file changes. Append or modify 
an existing records.yaml field
diff --git a/src/traffic_ctl/traffic_ctl.cc b/src/traffic_ctl/traffic_ctl.cc
index 28e64f0ab3..33100cc01e 100644
--- a/src/traffic_ctl/traffic_ctl.cc
+++ b/src/traffic_ctl/traffic_ctl.cc
@@ -78,7 +78,9 @@ main([[maybe_unused]] int argc, const char **argv)
     .add_option("--version", "-V", "Print version string")
     .add_option("--help", "-h", "Print usage information")
     .add_option("--run-root", "", "using TS_RUNROOT as sandbox", "TS_RUNROOT", 
1)
-    .add_option("--format", "-f", "Use a specific output format {json|rpc}", 
"", 1, "", "format");
+    .add_option("--format", "-f", "Use a specific output format {json|rpc}", 
"", 1, "", "format")
+    .add_option("--read-timeout-ms", "", "Read timeout for RPC (in 
milliseconds)", "", 1, "10000", "read-timeout")
+    .add_option("--read-attempts", "", "Read attempts for RPC", "", 1, "100", 
"read-attempts");
 
   auto &config_command     = parser.add_command("config", "Manipulate 
configuration records").require_commands();
   auto &metric_command     = parser.add_command("metric", "Manipulate 
performance metrics").require_commands();
diff --git a/src/traffic_top/stats.h b/src/traffic_top/stats.h
index bcdcfb4023..035151eb5e 100644
--- a/src/traffic_top/stats.h
+++ b/src/traffic_top/stats.h
@@ -22,6 +22,7 @@
 */
 #pragma once
 
+#include <chrono>
 #include <map>
 #include <string>
 #include <sys/types.h>
@@ -483,7 +484,7 @@ private:
       rpc::RPCClient rpcClient;
 
       // invoke the rpc.
-      auto const &rpcResponse = rpcClient.invoke<>(request);
+      auto const &rpcResponse = rpcClient.invoke<>(request, 
std::chrono::milliseconds(1000), 10);
 
       if (!rpcResponse.is_error()) {
         auto const &records = 
rpcResponse.result.as<rpc::RecordLookUpResponse>();

Reply via email to