From edf500fb8259680b773f5271bbeaf61b167b04bb Mon Sep 17 00:00:00 2001 From: Vijay Pai Date: Mon, 3 May 2021 12:16:12 -0700 Subject: [PATCH] Add useful status error message when server threadpool is exhausted (#26146) --- include/grpcpp/impl/codegen/method_handler.h | 12 +++++++++--- src/cpp/server/server_cc.cc | 19 +++++++++++++++---- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/include/grpcpp/impl/codegen/method_handler.h b/include/grpcpp/impl/codegen/method_handler.h index 756f4aae751..fb093f54b82 100644 --- a/include/grpcpp/impl/codegen/method_handler.h +++ b/include/grpcpp/impl/codegen/method_handler.h @@ -357,9 +357,12 @@ class SplitServerStreamingHandler template <::grpc::StatusCode code> class ErrorMethodHandler : public ::grpc::internal::MethodHandler { public: + explicit ErrorMethodHandler(const std::string& message) : message_(message) {} + template - static void FillOps(::grpc::ServerContextBase* context, T* ops) { - ::grpc::Status status(code, ""); + static void FillOps(::grpc::ServerContextBase* context, + const std::string& message, T* ops) { + ::grpc::Status status(code, message); if (!context->sent_initial_metadata_) { ops->SendInitialMetadata(&context->initial_metadata_, context->initial_metadata_flags()); @@ -375,7 +378,7 @@ class ErrorMethodHandler : public ::grpc::internal::MethodHandler { ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, ::grpc::internal::CallOpServerSendStatus> ops; - FillOps(param.server_context, &ops); + FillOps(param.server_context, message_, &ops); param.call->PerformOps(&ops); param.call->cq()->Pluck(&ops); } @@ -388,6 +391,9 @@ class ErrorMethodHandler : public ::grpc::internal::MethodHandler { } return nullptr; } + + private: + const std::string message_; }; typedef ErrorMethodHandler<::grpc::StatusCode::UNIMPLEMENTED> diff --git a/src/cpp/server/server_cc.cc b/src/cpp/server/server_cc.cc index d8f5af5e35f..a334cdd867c 100644 --- a/src/cpp/server/server_cc.cc +++ b/src/cpp/server/server_cc.cc @@ -67,6 +67,15 @@ namespace { // max-threads set) to the server builder. #define DEFAULT_MAX_SYNC_SERVER_THREADS INT_MAX +// Give a useful status error message if the resource is exhausted specifically +// because the server threadpool is full. +const char* kServerThreadpoolExhausted = "Server Threadpool Exhausted"; + +// Although we might like to give a useful status error message on unimplemented +// RPCs, it's not always possible since that also would need to be added across +// languages and isn't actually required by the spec. +const char* kUnknownRpcMethod = ""; + class DefaultGlobalCallbacks final : public Server::GlobalCallbacks { public: ~DefaultGlobalCallbacks() override {} @@ -802,7 +811,7 @@ class Server::SyncRequestThreadManager : public grpc::ThreadManager { if (has_sync_method_) { unknown_method_ = absl::make_unique( "unknown", grpc::internal::RpcMethod::BIDI_STREAMING, - new grpc::internal::UnknownMethodHandler); + new grpc::internal::UnknownMethodHandler(kUnknownRpcMethod)); server_->server()->core_server->SetBatchMethodAllocator( server_cq_->cq(), [this] { grpc_core::Server::BatchCallAllocation result; @@ -1194,7 +1203,8 @@ void Server::Start(grpc::ServerCompletionQueue** cqs, size_t num_cqs) { // to deal with the case of thread exhaustion if (sync_server_cqs_ != nullptr && !sync_server_cqs_->empty()) { resource_exhausted_handler_ = - absl::make_unique(); + absl::make_unique( + kServerThreadpoolExhausted); } for (const auto& value : sync_req_mgrs_) { @@ -1321,8 +1331,9 @@ bool Server::UnimplementedAsyncRequest::FinalizeResult(void** tag, Server::UnimplementedAsyncResponse::UnimplementedAsyncResponse( UnimplementedAsyncRequest* request) : request_(request) { - grpc::Status status(grpc::StatusCode::UNIMPLEMENTED, ""); - grpc::internal::UnknownMethodHandler::FillOps(request_->context(), this); + grpc::Status status(grpc::StatusCode::UNIMPLEMENTED, kUnknownRpcMethod); + grpc::internal::UnknownMethodHandler::FillOps(request_->context(), + kUnknownRpcMethod, this); request_->stream()->call_.PerformOps(this); }