From c2261c6f280f0bda67060d0b8ffc593df852b625 Mon Sep 17 00:00:00 2001 From: Yash Tibrewal Date: Fri, 8 Dec 2023 14:34:26 -0800 Subject: [PATCH] [example] Add WAIT_FOR_READY example (#35219) --- examples/cpp/wait_for_ready/BUILD | 27 +++++ examples/cpp/wait_for_ready/CMakeLists.txt | 70 ++++++++++++ examples/cpp/wait_for_ready/README.md | 32 ++++++ .../wait_for_ready/greeter_callback_client.cc | 107 ++++++++++++++++++ 4 files changed, 236 insertions(+) create mode 100644 examples/cpp/wait_for_ready/BUILD create mode 100644 examples/cpp/wait_for_ready/CMakeLists.txt create mode 100644 examples/cpp/wait_for_ready/README.md create mode 100644 examples/cpp/wait_for_ready/greeter_callback_client.cc diff --git a/examples/cpp/wait_for_ready/BUILD b/examples/cpp/wait_for_ready/BUILD new file mode 100644 index 0000000000000..00047fa2f9bd3 --- /dev/null +++ b/examples/cpp/wait_for_ready/BUILD @@ -0,0 +1,27 @@ +# Copyright 2023 the gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +licenses(["notice"]) + +cc_binary( + name = "greeter_callback_client", + srcs = ["greeter_callback_client.cc"], + defines = ["BAZEL_BUILD"], + deps = [ + "//:grpc++", + "//examples/protos:helloworld_cc_grpc", + "@com_google_absl//absl/flags:flag", + "@com_google_absl//absl/flags:parse", + ], +) diff --git a/examples/cpp/wait_for_ready/CMakeLists.txt b/examples/cpp/wait_for_ready/CMakeLists.txt new file mode 100644 index 0000000000000..06024dfbc9b8b --- /dev/null +++ b/examples/cpp/wait_for_ready/CMakeLists.txt @@ -0,0 +1,70 @@ +# Copyright 2018 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# cmake build file for C++ helloworld example. +# Assumes protobuf and gRPC have been installed using cmake. +# See cmake_externalproject/CMakeLists.txt for all-in-one cmake build +# that automatically builds all the dependencies before building helloworld. + +cmake_minimum_required(VERSION 3.8) + +project(HelloWorld C CXX) + +include(../cmake/common.cmake) + +# Proto file +get_filename_component(hw_proto "../../protos/helloworld.proto" ABSOLUTE) +get_filename_component(hw_proto_path "${hw_proto}" PATH) + +# Generated sources +set(hw_proto_srcs "${CMAKE_CURRENT_BINARY_DIR}/helloworld.pb.cc") +set(hw_proto_hdrs "${CMAKE_CURRENT_BINARY_DIR}/helloworld.pb.h") +set(hw_grpc_srcs "${CMAKE_CURRENT_BINARY_DIR}/helloworld.grpc.pb.cc") +set(hw_grpc_hdrs "${CMAKE_CURRENT_BINARY_DIR}/helloworld.grpc.pb.h") +add_custom_command( + OUTPUT "${hw_proto_srcs}" "${hw_proto_hdrs}" "${hw_grpc_srcs}" "${hw_grpc_hdrs}" + COMMAND ${_PROTOBUF_PROTOC} + ARGS --grpc_out "${CMAKE_CURRENT_BINARY_DIR}" + --cpp_out "${CMAKE_CURRENT_BINARY_DIR}" + -I "${hw_proto_path}" + --plugin=protoc-gen-grpc="${_GRPC_CPP_PLUGIN_EXECUTABLE}" + "${hw_proto}" + DEPENDS "${hw_proto}") + +# Include generated *.pb.h files +include_directories("${CMAKE_CURRENT_BINARY_DIR}") + +# hw_grpc_proto +add_library(hw_grpc_proto + ${hw_grpc_srcs} + ${hw_grpc_hdrs} + ${hw_proto_srcs} + ${hw_proto_hdrs}) +target_link_libraries(hw_grpc_proto + ${_REFLECTION} + ${_GRPC_GRPCPP} + ${_PROTOBUF_LIBPROTOBUF}) + +# Targets greeter_[async_](client|server) +foreach(_target + greeter_callback_client greeter_callback_server + add_executable(${_target} "${_target}.cc") + target_link_libraries(${_target} + hw_grpc_proto + absl::flags + absl::flags_parse + ${_REFLECTION} + ${_GRPC_GRPCPP} + ${_PROTOBUF_LIBPROTOBUF}) +endforeach() diff --git a/examples/cpp/wait_for_ready/README.md b/examples/cpp/wait_for_ready/README.md new file mode 100644 index 0000000000000..1de220b99a33b --- /dev/null +++ b/examples/cpp/wait_for_ready/README.md @@ -0,0 +1,32 @@ +# gRPC C++ Wait-For-Ready Example + +The Wait-For-Ready example builds on the +[Hello World Example](https://github.com/grpc/grpc/tree/master/examples/cpp/helloworld) +and changes the gRPC client and server to show how to set wait-for-ready. + +For more information on wait-for-ready in gRPC, please refer to +[gRPC Wait For Ready Semantics](https://github.com/grpc/grpc/blob/master/doc/wait-for-ready.md). + +## Running the example + +First run the client - + +``` +$ tools/bazel run examples/cpp/wait_for_ready:greeter_callback_client +``` + +On running this, we'll see 10 RPCs failed due to "Connection refused" errors. +These RPCs did not have WAIT_FOR_READY set, resulting in the RPCs not waiting +for the channel to be connected. + +The next 10 RPCs have WAIT_FOR_READY set, so the client will be waiting for the +channel to be ready before progressing. + +Now, on a separate terminal, run the server - + +``` +$ tools/bazel run examples/cpp/helloworld:greeter_callback_server +``` + +The client channel should now be able to connect to the server, and the RPCs +should succeed. diff --git a/examples/cpp/wait_for_ready/greeter_callback_client.cc b/examples/cpp/wait_for_ready/greeter_callback_client.cc new file mode 100644 index 0000000000000..1c7865ed2bfaf --- /dev/null +++ b/examples/cpp/wait_for_ready/greeter_callback_client.cc @@ -0,0 +1,107 @@ +// +// +// Copyright 2023 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// + +#include +#include +#include +#include +#include +#include + +#include "absl/flags/flag.h" +#include "absl/flags/parse.h" + +#include + +#ifdef BAZEL_BUILD +#include "examples/protos/helloworld.grpc.pb.h" +#else +#include "helloworld.grpc.pb.h" +#endif + +ABSL_FLAG(std::string, target, "localhost:50051", "Server address"); + +using grpc::Channel; +using grpc::ClientContext; +using grpc::Status; +using helloworld::Greeter; +using helloworld::HelloReply; +using helloworld::HelloRequest; + +class GreeterClient { + public: + GreeterClient(std::shared_ptr channel) + : stub_(Greeter::NewStub(channel)) {} + + // Assembles the client's payload, sends it and presents the response back + // from the server. + std::string SayHello(const std::string& user, bool wait_for_ready) { + HelloRequest request; + request.set_name(user); + HelloReply reply; + ClientContext context; + context.set_wait_for_ready(wait_for_ready); + std::mutex mu; + std::condition_variable cv; + bool done = false; + Status status; + stub_->async()->SayHello(&context, &request, &reply, + [&mu, &cv, &done, &status](Status s) { + status = std::move(s); + std::lock_guard lock(mu); + done = true; + cv.notify_one(); + }); + + std::unique_lock lock(mu); + while (!done) { + cv.wait(lock); + } + if (status.ok()) { + return reply.message(); + } else { + std::cout << status.error_code() << ": " << status.error_message() + << "\n"; + return "RPC failed"; + } + } + + private: + std::unique_ptr stub_; +}; + +int main(int argc, char** argv) { + absl::ParseCommandLine(argc, argv); + std::string target_str = absl::GetFlag(FLAGS_target); + GreeterClient greeter( + grpc::CreateChannel(target_str, grpc::InsecureChannelCredentials())); + std::string user("world"); + // First send an RPC without wait_for_ready. If the server is not running, + // this RPC will fail immediately. + std::cout << "Greeter received: " + << greeter.SayHello(user, /*wait_for_ready=*/false) << "\n"; + std::cout << "\nWe will now send RPCs with wait_for_ready set. If the " + "server is not running already, please start it now.\n"; + // Now send RPC with wait_for_ready for set. Even if the server is not + // running, the RPC will still wait for the deadline to expire before + // failing. + std::cout << "Greeter received: " + << greeter.SayHello(user, /*wait_for_ready=*/true) << "\n"; + + return 0; +}