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>();