commit
42c5ad0f79
3874 changed files with 255980 additions and 214567 deletions
@ -1 +1 @@ |
|||||||
6.3.2 |
6.4.0 |
||||||
|
@ -1,32 +0,0 @@ |
|||||||
name: PR Title Check & Tag |
|
||||||
on: |
|
||||||
pull_request_target: |
|
||||||
types: [opened, reopened, synchronize, edited] |
|
||||||
permissions: |
|
||||||
contents: read # to determine modified files (actions/labeler) |
|
||||||
|
|
||||||
jobs: |
|
||||||
triage: |
|
||||||
permissions: |
|
||||||
contents: read # to determine modified files (actions/labeler) |
|
||||||
pull-requests: write # to add labels to PRs (actions/labeler) |
|
||||||
|
|
||||||
runs-on: ubuntu-latest |
|
||||||
steps: |
|
||||||
- uses: actions/labeler@v3 |
|
||||||
with: |
|
||||||
repo-token: "${{ secrets.GITHUB_TOKEN }}" |
|
||||||
sync-labels: "" |
|
||||||
|
|
||||||
title-check: |
|
||||||
permissions: |
|
||||||
contents: read |
|
||||||
pull-requests: write |
|
||||||
|
|
||||||
runs-on: ubuntu-latest |
|
||||||
steps: |
|
||||||
- uses: thehanimo/pr-title-checker@v1.3.5 |
|
||||||
with: |
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
|
||||||
pass_on_octokit_error: false |
|
||||||
configuration_path: ".github/pr_title_checker_config.json" |
|
@ -0,0 +1,19 @@ |
|||||||
|
name: PR Auto Tag |
||||||
|
on: |
||||||
|
pull_request_target: |
||||||
|
types: [opened, reopened, synchronize, edited] |
||||||
|
permissions: |
||||||
|
contents: read # to determine modified files (actions/labeler) |
||||||
|
|
||||||
|
jobs: |
||||||
|
triage: |
||||||
|
permissions: |
||||||
|
contents: read # to determine modified files (actions/labeler) |
||||||
|
pull-requests: write # to add labels to PRs (actions/labeler) |
||||||
|
|
||||||
|
runs-on: ubuntu-latest |
||||||
|
steps: |
||||||
|
- uses: actions/labeler@v3 |
||||||
|
with: |
||||||
|
repo-token: "${{ secrets.GITHUB_TOKEN }}" |
||||||
|
sync-labels: "" |
File diff suppressed because it is too large
Load Diff
@ -1,3 +0,0 @@ |
|||||||
# Top level ownership |
|
||||||
@markdroth **/OWNERS |
|
||||||
@a11r **/OWNERS |
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +0,0 @@ |
|||||||
set noparent |
|
||||||
@jtattermusch |
|
||||||
@veblush |
|
||||||
@gnossen |
|
||||||
|
|
@ -1,2 +1 @@ |
|||||||
6.3.2 |
6.4.0 |
||||||
5.4.1 |
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,3 +0,0 @@ |
|||||||
set noparent |
|
||||||
@jtattermusch |
|
||||||
@apolcyn |
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,39 @@ |
|||||||
|
# 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 = "client", |
||||||
|
srcs = ["client.cc"], |
||||||
|
defines = ["BAZEL_BUILD"], |
||||||
|
deps = [ |
||||||
|
"//:grpc++", |
||||||
|
"//examples/protos:helloworld_cc_grpc", |
||||||
|
"@com_google_absl//absl/flags:flag", |
||||||
|
"@com_google_absl//absl/flags:parse", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
cc_binary( |
||||||
|
name = "server", |
||||||
|
srcs = ["server.cc"], |
||||||
|
defines = ["BAZEL_BUILD"], |
||||||
|
deps = [ |
||||||
|
"//:grpc++", |
||||||
|
"//examples/protos:helloworld_cc_grpc", |
||||||
|
"@com_google_absl//absl/flags:flag", |
||||||
|
"@com_google_absl//absl/flags:parse", |
||||||
|
], |
||||||
|
) |
@ -0,0 +1,71 @@ |
|||||||
|
# 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. |
||||||
|
# |
||||||
|
# cmake build file for C++ keyvaluestore 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 keyvaluestore. |
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.8) |
||||||
|
|
||||||
|
project(Cancellation C CXX) |
||||||
|
|
||||||
|
include(../cmake/common.cmake) |
||||||
|
|
||||||
|
# Proto files |
||||||
|
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_(client|server) |
||||||
|
foreach(_target |
||||||
|
client server) |
||||||
|
add_executable(${_target} "${_target}.cc") |
||||||
|
target_link_libraries(${_target} |
||||||
|
hw_grpc_proto |
||||||
|
absl::flags |
||||||
|
absl::flags_parse |
||||||
|
absl::strings |
||||||
|
${_REFLECTION} |
||||||
|
${_GRPC_GRPCPP} |
||||||
|
${_PROTOBUF_LIBPROTOBUF}) |
||||||
|
endforeach() |
@ -0,0 +1,37 @@ |
|||||||
|
# Cancellation Example |
||||||
|
|
||||||
|
## Overview |
||||||
|
|
||||||
|
This example shows you how to cancel from the client and how to get informed on the server and the client. |
||||||
|
|
||||||
|
### Try it! |
||||||
|
|
||||||
|
Once you have working gRPC, you can build this example using either bazel or cmake. |
||||||
|
|
||||||
|
Run the server, which will listen on port 50051: |
||||||
|
|
||||||
|
```sh |
||||||
|
$ ./server |
||||||
|
``` |
||||||
|
|
||||||
|
Run the client (in a different terminal): |
||||||
|
|
||||||
|
```sh |
||||||
|
$ ./client |
||||||
|
``` |
||||||
|
|
||||||
|
If things go smoothly, you will see the client output: |
||||||
|
|
||||||
|
``` |
||||||
|
Begin : Begin Ack |
||||||
|
Count 1 : Count 1 Ack |
||||||
|
Count 2 : Count 2 Ack |
||||||
|
Count 3 : Count 3 Ack |
||||||
|
Count 4 : Count 4 Ack |
||||||
|
Count 5 : Count 5 Ack |
||||||
|
Count 6 : Count 6 Ack |
||||||
|
Count 7 : Count 7 Ack |
||||||
|
Count 8 : Count 8 Ack |
||||||
|
Count 9 : Count 9 Ack |
||||||
|
RPC Cancelled! |
||||||
|
``` |
@ -0,0 +1,119 @@ |
|||||||
|
// 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 <condition_variable> |
||||||
|
#include <iostream> |
||||||
|
#include <memory> |
||||||
|
#include <mutex> |
||||||
|
#include <string> |
||||||
|
#include <vector> |
||||||
|
|
||||||
|
#include "absl/flags/flag.h" |
||||||
|
#include "absl/flags/parse.h" |
||||||
|
#include "absl/strings/str_cat.h" |
||||||
|
|
||||||
|
#include <grpcpp/grpcpp.h> |
||||||
|
|
||||||
|
#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 grpc::StatusCode; |
||||||
|
using helloworld::Greeter; |
||||||
|
using helloworld::HelloReply; |
||||||
|
using helloworld::HelloRequest; |
||||||
|
|
||||||
|
// Requests each key in the vector and displays the key and its corresponding
|
||||||
|
// value as a pair.
|
||||||
|
class KeyValueStoreClient |
||||||
|
: public grpc::ClientBidiReactor<HelloRequest, HelloReply> { |
||||||
|
public: |
||||||
|
KeyValueStoreClient(std::shared_ptr<Channel> channel) |
||||||
|
: stub_(Greeter::NewStub(channel)) { |
||||||
|
stub_->async()->SayHelloBidiStream(&context_, this); |
||||||
|
request_.set_name("Begin"); |
||||||
|
StartWrite(&request_); |
||||||
|
StartCall(); |
||||||
|
} |
||||||
|
|
||||||
|
void OnReadDone(bool ok) override { |
||||||
|
if (ok) { |
||||||
|
std::cout << request_.name() << " : " << response_.message() << std::endl; |
||||||
|
if (++counter_ < 10) { |
||||||
|
request_.set_name(absl::StrCat("Count ", counter_)); |
||||||
|
StartWrite(&request_); |
||||||
|
} else { |
||||||
|
// Cancel after sending 10 messages
|
||||||
|
context_.TryCancel(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void OnWriteDone(bool ok) override { |
||||||
|
if (ok) { |
||||||
|
StartRead(&response_); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void OnDone(const grpc::Status& status) override { |
||||||
|
if (!status.ok()) { |
||||||
|
if (status.error_code() == StatusCode::CANCELLED) { |
||||||
|
// Eventually client will know here that call is cancelled.
|
||||||
|
std::cout << "RPC Cancelled!" << std::endl; |
||||||
|
} else { |
||||||
|
std::cout << "RPC Failed: " << status.error_code() << ": " |
||||||
|
<< status.error_message() << std::endl; |
||||||
|
} |
||||||
|
} |
||||||
|
std::unique_lock<std::mutex> l(mu_); |
||||||
|
done_ = true; |
||||||
|
cv_.notify_all(); |
||||||
|
} |
||||||
|
|
||||||
|
void Await() { |
||||||
|
std::unique_lock<std::mutex> l(mu_); |
||||||
|
while (!done_) { |
||||||
|
cv_.wait(l); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
std::unique_ptr<Greeter::Stub> stub_; |
||||||
|
size_t counter_ = 0; |
||||||
|
ClientContext context_; |
||||||
|
bool done_ = false; |
||||||
|
HelloRequest request_; |
||||||
|
HelloReply response_; |
||||||
|
std::mutex mu_; |
||||||
|
std::condition_variable cv_; |
||||||
|
}; |
||||||
|
|
||||||
|
int main(int argc, char** argv) { |
||||||
|
absl::ParseCommandLine(argc, argv); |
||||||
|
// Instantiate the client. It requires a channel, out of which the actual RPCs
|
||||||
|
// are created. This channel models a connection to an endpoint specified by
|
||||||
|
// the argument "--target=" which is the only expected argument.
|
||||||
|
std::string target_str = absl::GetFlag(FLAGS_target); |
||||||
|
KeyValueStoreClient client( |
||||||
|
grpc::CreateChannel(target_str, grpc::InsecureChannelCredentials())); |
||||||
|
client.Await(); |
||||||
|
return 0; |
||||||
|
} |
@ -0,0 +1,104 @@ |
|||||||
|
// 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 <iostream> |
||||||
|
#include <memory> |
||||||
|
#include <string> |
||||||
|
#include <vector> |
||||||
|
|
||||||
|
#include "absl/flags/flag.h" |
||||||
|
#include "absl/flags/parse.h" |
||||||
|
#include "absl/strings/str_format.h" |
||||||
|
|
||||||
|
#include <grpcpp/grpcpp.h> |
||||||
|
|
||||||
|
#ifdef BAZEL_BUILD |
||||||
|
#include "examples/protos/helloworld.grpc.pb.h" |
||||||
|
#else |
||||||
|
#include "helloworld.grpc.pb.h" |
||||||
|
#endif |
||||||
|
|
||||||
|
ABSL_FLAG(uint16_t, port, 50051, "Server port for the service"); |
||||||
|
|
||||||
|
using grpc::CallbackServerContext; |
||||||
|
using grpc::Server; |
||||||
|
using grpc::ServerBidiReactor; |
||||||
|
using grpc::ServerBuilder; |
||||||
|
using grpc::Status; |
||||||
|
using helloworld::Greeter; |
||||||
|
using helloworld::HelloReply; |
||||||
|
using helloworld::HelloRequest; |
||||||
|
|
||||||
|
// Logic behind the server's behavior.
|
||||||
|
class KeyValueStoreServiceImpl final : public Greeter::CallbackService { |
||||||
|
ServerBidiReactor<HelloRequest, HelloReply>* SayHelloBidiStream( |
||||||
|
CallbackServerContext* context) override { |
||||||
|
class Reactor : public ServerBidiReactor<HelloRequest, HelloReply> { |
||||||
|
public: |
||||||
|
explicit Reactor() { StartRead(&request_); } |
||||||
|
|
||||||
|
void OnReadDone(bool ok) override { |
||||||
|
if (!ok) { |
||||||
|
// Client cancelled it
|
||||||
|
std::cout << "OnReadDone Cancelled!" << std::endl; |
||||||
|
return Finish(grpc::Status::CANCELLED); |
||||||
|
} |
||||||
|
response_.set_message(absl::StrCat(request_.name(), " Ack")); |
||||||
|
StartWrite(&response_); |
||||||
|
} |
||||||
|
|
||||||
|
void OnWriteDone(bool ok) override { |
||||||
|
if (!ok) { |
||||||
|
// Client cancelled it
|
||||||
|
std::cout << "OnWriteDone Cancelled!" << std::endl; |
||||||
|
return Finish(grpc::Status::CANCELLED); |
||||||
|
} |
||||||
|
StartRead(&request_); |
||||||
|
} |
||||||
|
|
||||||
|
void OnDone() override { delete this; } |
||||||
|
|
||||||
|
private: |
||||||
|
HelloRequest request_; |
||||||
|
HelloReply response_; |
||||||
|
}; |
||||||
|
|
||||||
|
return new Reactor(); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
void RunServer(uint16_t port) { |
||||||
|
std::string server_address = absl::StrFormat("0.0.0.0:%d", port); |
||||||
|
KeyValueStoreServiceImpl service; |
||||||
|
|
||||||
|
ServerBuilder builder; |
||||||
|
// Listen on the given address without any authentication mechanism.
|
||||||
|
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); |
||||||
|
// Register "service" as the instance through which we'll communicate with
|
||||||
|
// clients. In this case it corresponds to an *synchronous* service.
|
||||||
|
builder.RegisterService(&service); |
||||||
|
// Finally assemble the server.
|
||||||
|
std::unique_ptr<Server> server(builder.BuildAndStart()); |
||||||
|
std::cout << "Server listening on " << server_address << std::endl; |
||||||
|
|
||||||
|
// Wait for the server to shutdown. Note that some other thread must be
|
||||||
|
// responsible for shutting down the server for this call to ever return.
|
||||||
|
server->Wait(); |
||||||
|
} |
||||||
|
|
||||||
|
int main(int argc, char** argv) { |
||||||
|
absl::ParseCommandLine(argc, argv); |
||||||
|
RunServer(absl::GetFlag(FLAGS_port)); |
||||||
|
return 0; |
||||||
|
} |
@ -0,0 +1,47 @@ |
|||||||
|
# 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 = "csm_greeter_client", |
||||||
|
srcs = ["csm_greeter_client.cc"], |
||||||
|
defines = ["BAZEL_BUILD"], |
||||||
|
deps = [ |
||||||
|
"//:grpc++", |
||||||
|
"//:grpcpp_csm_observability", |
||||||
|
"//examples/protos:helloworld_cc_grpc", |
||||||
|
"@com_google_absl//absl/flags:flag", |
||||||
|
"@com_google_absl//absl/flags:parse", |
||||||
|
"@io_opentelemetry_cpp//exporters/prometheus:prometheus_exporter", |
||||||
|
"@io_opentelemetry_cpp//sdk/src/metrics", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
cc_binary( |
||||||
|
name = "csm_greeter_server", |
||||||
|
srcs = ["csm_greeter_server.cc"], |
||||||
|
defines = ["BAZEL_BUILD"], |
||||||
|
deps = [ |
||||||
|
"//:grpc++", |
||||||
|
"//:grpc++_reflection", |
||||||
|
"//:grpcpp_admin", |
||||||
|
"//:grpcpp_csm_observability", |
||||||
|
"//examples/protos:helloworld_cc_grpc", |
||||||
|
"@com_google_absl//absl/flags:flag", |
||||||
|
"@com_google_absl//absl/flags:parse", |
||||||
|
"@io_opentelemetry_cpp//exporters/prometheus:prometheus_exporter", |
||||||
|
"@io_opentelemetry_cpp//sdk/src/metrics", |
||||||
|
], |
||||||
|
) |
@ -0,0 +1,39 @@ |
|||||||
|
# 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. |
||||||
|
|
||||||
|
FROM python:3.9-slim-bookworm |
||||||
|
|
||||||
|
RUN apt-get update -y && apt-get upgrade -y && apt-get install -y build-essential clang curl |
||||||
|
|
||||||
|
WORKDIR /workdir |
||||||
|
|
||||||
|
RUN ln -s /usr/bin/python3 /usr/bin/python |
||||||
|
RUN mkdir /artifacts |
||||||
|
|
||||||
|
COPY . . |
||||||
|
RUN OVERRIDE_BAZEL_VERSION=5.4.0 tools/bazel build //examples/cpp/csm:csm_greeter_client |
||||||
|
RUN cp -rL /workdir/bazel-bin/examples/cpp/csm/csm_greeter_client /artifacts/ |
||||||
|
|
||||||
|
FROM python:3.9-slim-bookworm |
||||||
|
|
||||||
|
RUN apt-get update \ |
||||||
|
&& apt-get -y upgrade \ |
||||||
|
&& apt-get -y autoremove \ |
||||||
|
&& apt-get install -y curl |
||||||
|
|
||||||
|
COPY --from=0 /artifacts ./ |
||||||
|
|
||||||
|
ENV GRPC_EXPERIMENTAL_XDS_ENABLE_OVERRIDE_HOST=true |
||||||
|
|
||||||
|
ENTRYPOINT ["/csm_greeter_client"] |
@ -0,0 +1,39 @@ |
|||||||
|
# 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. |
||||||
|
|
||||||
|
FROM python:3.9-slim-bookworm |
||||||
|
|
||||||
|
RUN apt-get update -y && apt-get upgrade -y && apt-get install -y build-essential clang curl |
||||||
|
|
||||||
|
WORKDIR /workdir |
||||||
|
|
||||||
|
RUN ln -s /usr/bin/python3 /usr/bin/python |
||||||
|
RUN mkdir /artifacts |
||||||
|
|
||||||
|
COPY . . |
||||||
|
RUN OVERRIDE_BAZEL_VERSION=5.4.0 tools/bazel build //examples/cpp/csm:csm_greeter_server |
||||||
|
RUN cp -rL /workdir/bazel-bin/examples/cpp/csm/csm_greeter_server /artifacts/ |
||||||
|
|
||||||
|
FROM python:3.9-slim-bookworm |
||||||
|
|
||||||
|
RUN apt-get update \ |
||||||
|
&& apt-get -y upgrade \ |
||||||
|
&& apt-get -y autoremove \ |
||||||
|
&& apt-get install -y curl |
||||||
|
|
||||||
|
COPY --from=0 /artifacts ./ |
||||||
|
|
||||||
|
ENV GRPC_EXPERIMENTAL_XDS_ENABLE_OVERRIDE_HOST=true |
||||||
|
|
||||||
|
ENTRYPOINT ["/csm_greeter_server"] |
@ -0,0 +1,11 @@ |
|||||||
|
# gRPC C++ CSM Hello World Example |
||||||
|
|
||||||
|
This CSM 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 accept configuration from an xDS control plane and test SSA and CSM observability |
||||||
|
|
||||||
|
## Configuration |
||||||
|
|
||||||
|
The client takes the following command-line arguments - |
||||||
|
* target - By default, the client tries to connect to the xDS "xds:///helloworld:50051" and gRPC would use xDS to resolve this target and connect to the server backend. This can be overriden to change the target. |
||||||
|
|
||||||
|
The server takes the following command-line arguments - |
||||||
|
* port - Port on which the Hello World service is run. Defaults to 50051. |
@ -0,0 +1,200 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* 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 <condition_variable> |
||||||
|
#include <iostream> |
||||||
|
#include <memory> |
||||||
|
#include <mutex> |
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include "absl/flags/flag.h" |
||||||
|
#include "absl/flags/parse.h" |
||||||
|
#include "absl/strings/str_split.h" |
||||||
|
#include "opentelemetry/exporters/prometheus/exporter_factory.h" |
||||||
|
#include "opentelemetry/exporters/prometheus/exporter_options.h" |
||||||
|
#include "opentelemetry/sdk/metrics/meter_provider.h" |
||||||
|
|
||||||
|
#include <grpcpp/ext/csm_observability.h> |
||||||
|
#include <grpcpp/grpcpp.h> |
||||||
|
#include <grpcpp/support/string_ref.h> |
||||||
|
|
||||||
|
#ifdef BAZEL_BUILD |
||||||
|
#include "examples/protos/helloworld.grpc.pb.h" |
||||||
|
#else |
||||||
|
#include "helloworld.grpc.pb.h" |
||||||
|
#endif |
||||||
|
|
||||||
|
ABSL_FLAG(std::string, target, "xds:///helloworld:50051", "Target string"); |
||||||
|
|
||||||
|
using grpc::Channel; |
||||||
|
using grpc::ClientContext; |
||||||
|
using grpc::Status; |
||||||
|
using helloworld::Greeter; |
||||||
|
using helloworld::HelloReply; |
||||||
|
using helloworld::HelloRequest; |
||||||
|
|
||||||
|
struct Cookie { |
||||||
|
std::string name; |
||||||
|
std::string value; |
||||||
|
std::set<std::string> attributes; |
||||||
|
|
||||||
|
std::pair<std::string, std::string> Header() const { |
||||||
|
return std::make_pair("cookie", absl::StrFormat("%s=%s", name, value)); |
||||||
|
} |
||||||
|
|
||||||
|
template <typename Sink> |
||||||
|
friend void AbslStringify(Sink& sink, const Cookie& cookie) { |
||||||
|
absl::Format(&sink, "(Cookie: %s, value: %s, attributes: {%s})", |
||||||
|
cookie.name, cookie.value, |
||||||
|
absl::StrJoin(cookie.attributes, ", ")); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
class GreeterClient { |
||||||
|
protected: |
||||||
|
static Cookie ParseCookie(absl::string_view header) { |
||||||
|
Cookie cookie; |
||||||
|
std::pair<absl::string_view, absl::string_view> name_value = |
||||||
|
absl::StrSplit(header, absl::MaxSplits('=', 1)); |
||||||
|
cookie.name = std::string(name_value.first); |
||||||
|
std::pair<absl::string_view, absl::string_view> value_attrs = |
||||||
|
absl::StrSplit(name_value.second, absl::MaxSplits(';', 1)); |
||||||
|
cookie.value = std::string(value_attrs.first); |
||||||
|
for (absl::string_view segment : absl::StrSplit(value_attrs.second, ';')) { |
||||||
|
cookie.attributes.emplace(absl::StripAsciiWhitespace(segment)); |
||||||
|
} |
||||||
|
return cookie; |
||||||
|
} |
||||||
|
|
||||||
|
static std::vector<Cookie> GetCookies( |
||||||
|
const std::multimap<grpc::string_ref, grpc::string_ref>& |
||||||
|
server_initial_metadata, |
||||||
|
absl::string_view cookie_name) { |
||||||
|
std::vector<Cookie> values; |
||||||
|
auto pair = server_initial_metadata.equal_range("set-cookie"); |
||||||
|
for (auto it = pair.first; it != pair.second; ++it) { |
||||||
|
gpr_log(GPR_INFO, "set-cookie header: %s", it->second.data()); |
||||||
|
const auto cookie = ParseCookie(it->second.data()); |
||||||
|
if (cookie.name == cookie_name) { |
||||||
|
values.emplace_back(cookie); |
||||||
|
} |
||||||
|
} |
||||||
|
return values; |
||||||
|
} |
||||||
|
|
||||||
|
public: |
||||||
|
GreeterClient(std::shared_ptr<Channel> 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, Cookie* cookieFromServer, |
||||||
|
const Cookie* cookieToServer) { |
||||||
|
// Data we are sending to the server.
|
||||||
|
HelloRequest request; |
||||||
|
request.set_name(user); |
||||||
|
|
||||||
|
// Container for the data we expect from the server.
|
||||||
|
HelloReply reply; |
||||||
|
|
||||||
|
// Context for the client. It could be used to convey extra information to
|
||||||
|
// the server and/or tweak certain RPC behaviors.
|
||||||
|
ClientContext context; |
||||||
|
|
||||||
|
// The actual RPC.
|
||||||
|
std::mutex mu; |
||||||
|
std::condition_variable cv; |
||||||
|
bool done = false; |
||||||
|
Status status; |
||||||
|
if (cookieToServer != NULL) { |
||||||
|
std::pair<std::string, std::string> cookieHeader = |
||||||
|
cookieToServer->Header(); |
||||||
|
context.AddMetadata(cookieHeader.first, cookieHeader.second); |
||||||
|
} |
||||||
|
stub_->async()->SayHello(&context, &request, &reply, |
||||||
|
[&mu, &cv, &done, &status](Status s) { |
||||||
|
status = std::move(s); |
||||||
|
std::lock_guard<std::mutex> lock(mu); |
||||||
|
done = true; |
||||||
|
cv.notify_one(); |
||||||
|
}); |
||||||
|
|
||||||
|
std::unique_lock<std::mutex> lock(mu); |
||||||
|
while (!done) { |
||||||
|
cv.wait(lock); |
||||||
|
} |
||||||
|
|
||||||
|
// Act upon its status.
|
||||||
|
if (status.ok()) { |
||||||
|
if (cookieFromServer != NULL) { |
||||||
|
const std::multimap<grpc::string_ref, grpc::string_ref>& |
||||||
|
server_initial_metadata = context.GetServerInitialMetadata(); |
||||||
|
std::vector<Cookie> cookies = |
||||||
|
GetCookies(server_initial_metadata, "GSSA"); |
||||||
|
if (!cookies.empty()) { |
||||||
|
*cookieFromServer = cookies.front(); |
||||||
|
} |
||||||
|
} |
||||||
|
return reply.message(); |
||||||
|
} else { |
||||||
|
std::cout << status.error_code() << ": " << status.error_message() |
||||||
|
<< std::endl; |
||||||
|
return "RPC failed"; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
std::unique_ptr<Greeter::Stub> stub_; |
||||||
|
}; |
||||||
|
|
||||||
|
static void sayHello(GreeterClient& greeter, Cookie* cookieFromServer, |
||||||
|
const Cookie* cookieToServer) { |
||||||
|
std::string user("world"); |
||||||
|
std::string reply = greeter.SayHello(user, cookieFromServer, cookieToServer); |
||||||
|
std::cout << "Greeter received: " << reply << std::endl; |
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(5)); |
||||||
|
} |
||||||
|
|
||||||
|
int main(int argc, char** argv) { |
||||||
|
absl::ParseCommandLine(argc, argv); |
||||||
|
opentelemetry::exporter::metrics::PrometheusExporterOptions opts; |
||||||
|
// default was "localhost:9464" which causes connection issue across GKE pods
|
||||||
|
opts.url = "0.0.0.0:9464"; |
||||||
|
auto prometheus_exporter = |
||||||
|
opentelemetry::exporter::metrics::PrometheusExporterFactory::Create(opts); |
||||||
|
auto meter_provider = |
||||||
|
std::make_shared<opentelemetry::sdk::metrics::MeterProvider>(); |
||||||
|
meter_provider->AddMetricReader(std::move(prometheus_exporter)); |
||||||
|
auto observability = grpc::experimental::CsmObservabilityBuilder() |
||||||
|
.SetMeterProvider(std::move(meter_provider)) |
||||||
|
.BuildAndRegister(); |
||||||
|
if (!observability.ok()) { |
||||||
|
std::cerr << "CsmObservability::Init() failed: " |
||||||
|
<< observability.status().ToString() << std::endl; |
||||||
|
return static_cast<int>(observability.status().code()); |
||||||
|
} |
||||||
|
GreeterClient greeter(grpc::CreateChannel( |
||||||
|
absl::GetFlag(FLAGS_target), grpc::InsecureChannelCredentials())); |
||||||
|
|
||||||
|
Cookie session_cookie; |
||||||
|
sayHello(greeter, &session_cookie, NULL); |
||||||
|
while (true) { |
||||||
|
sayHello(greeter, NULL, &session_cookie); |
||||||
|
} |
||||||
|
return 0; |
||||||
|
} |
@ -0,0 +1,126 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* 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 <iostream> |
||||||
|
#include <memory> |
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include "absl/flags/flag.h" |
||||||
|
#include "absl/flags/parse.h" |
||||||
|
#include "absl/strings/str_cat.h" |
||||||
|
#include "opentelemetry/exporters/prometheus/exporter_factory.h" |
||||||
|
#include "opentelemetry/exporters/prometheus/exporter_options.h" |
||||||
|
#include "opentelemetry/sdk/metrics/meter_provider.h" |
||||||
|
|
||||||
|
#include <grpcpp/ext/admin_services.h> |
||||||
|
#include <grpcpp/ext/csm_observability.h> |
||||||
|
#include <grpcpp/ext/proto_server_reflection_plugin.h> |
||||||
|
#include <grpcpp/grpcpp.h> |
||||||
|
#include <grpcpp/health_check_service_interface.h> |
||||||
|
#include <grpcpp/xds_server_builder.h> |
||||||
|
|
||||||
|
#include "src/core/lib/iomgr/gethostname.h" |
||||||
|
|
||||||
|
#ifdef BAZEL_BUILD |
||||||
|
#include "examples/protos/helloworld.grpc.pb.h" |
||||||
|
#else |
||||||
|
#include "helloworld.grpc.pb.h" |
||||||
|
#endif |
||||||
|
|
||||||
|
ABSL_FLAG(int32_t, port, 50051, "Server port for service."); |
||||||
|
|
||||||
|
using grpc::CallbackServerContext; |
||||||
|
using grpc::Server; |
||||||
|
using grpc::ServerBuilder; |
||||||
|
using grpc::ServerUnaryReactor; |
||||||
|
using grpc::Status; |
||||||
|
using helloworld::Greeter; |
||||||
|
using helloworld::HelloReply; |
||||||
|
using helloworld::HelloRequest; |
||||||
|
|
||||||
|
// Logic and data behind the server's behavior.
|
||||||
|
class GreeterServiceImpl final : public Greeter::CallbackService { |
||||||
|
ServerUnaryReactor* SayHello(CallbackServerContext* context, |
||||||
|
const HelloRequest* request, |
||||||
|
HelloReply* reply) override { |
||||||
|
std::string prefix("Hello from "); |
||||||
|
prefix += my_name + " "; |
||||||
|
reply->set_message(prefix + request->name()); |
||||||
|
|
||||||
|
ServerUnaryReactor* reactor = context->DefaultReactor(); |
||||||
|
reactor->Finish(Status::OK); |
||||||
|
return reactor; |
||||||
|
} |
||||||
|
|
||||||
|
public: |
||||||
|
GreeterServiceImpl(const std::string& my_hostname) : my_name(my_hostname) {} |
||||||
|
|
||||||
|
private: |
||||||
|
const std::string my_name; |
||||||
|
}; |
||||||
|
|
||||||
|
void RunServer(const char* hostname) { |
||||||
|
grpc::EnableDefaultHealthCheckService(true); |
||||||
|
grpc::reflection::InitProtoReflectionServerBuilderPlugin(); |
||||||
|
int port = absl::GetFlag(FLAGS_port); |
||||||
|
grpc::XdsServerBuilder xds_builder; |
||||||
|
std::unique_ptr<Server> xds_enabled_server; |
||||||
|
|
||||||
|
std::string my_hostname(hostname); |
||||||
|
GreeterServiceImpl service(my_hostname); |
||||||
|
// Register "service" as the instance through which we'll communicate with
|
||||||
|
// clients. In this case it corresponds to an *synchronous* service.
|
||||||
|
xds_builder.RegisterService(&service); |
||||||
|
// Listen on the given address with XdsServerCredentials and a fallback of
|
||||||
|
// InsecureServerCredentials
|
||||||
|
xds_builder.AddListeningPort(absl::StrCat("0.0.0.0:", port), |
||||||
|
grpc::InsecureServerCredentials()); |
||||||
|
xds_enabled_server = xds_builder.BuildAndStart(); |
||||||
|
gpr_log(GPR_INFO, "Server starting on 0.0.0.0:%d", port); |
||||||
|
|
||||||
|
// Wait for the server to shutdown. Note that some other thread must be
|
||||||
|
// responsible for shutting down the server for this call to ever return.
|
||||||
|
xds_enabled_server->Wait(); |
||||||
|
} |
||||||
|
|
||||||
|
int main(int argc, char** argv) { |
||||||
|
absl::ParseCommandLine(argc, argv); |
||||||
|
opentelemetry::exporter::metrics::PrometheusExporterOptions opts; |
||||||
|
// default was "localhost:9464" which causes connection issue across GKE pods
|
||||||
|
opts.url = "0.0.0.0:9464"; |
||||||
|
auto prometheus_exporter = |
||||||
|
opentelemetry::exporter::metrics::PrometheusExporterFactory::Create(opts); |
||||||
|
auto meter_provider = |
||||||
|
std::make_shared<opentelemetry::sdk::metrics::MeterProvider>(); |
||||||
|
meter_provider->AddMetricReader(std::move(prometheus_exporter)); |
||||||
|
auto observability = grpc::experimental::CsmObservabilityBuilder() |
||||||
|
.SetMeterProvider(std::move(meter_provider)) |
||||||
|
.BuildAndRegister(); |
||||||
|
if (!observability.ok()) { |
||||||
|
std::cerr << "CsmObservability::Init() failed: " |
||||||
|
<< observability.status().ToString() << std::endl; |
||||||
|
return static_cast<int>(observability.status().code()); |
||||||
|
} |
||||||
|
const char* hostname = grpc_gethostname(); |
||||||
|
if (hostname == nullptr) { |
||||||
|
std::cout << "Failed to get hostname, terminating" << std::endl; |
||||||
|
return 1; |
||||||
|
} |
||||||
|
RunServer(hostname); |
||||||
|
return 0; |
||||||
|
} |
@ -0,0 +1,42 @@ |
|||||||
|
# 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 = "crashing_greeter_client", |
||||||
|
srcs = ["crashing_greeter_client.cc"], |
||||||
|
defines = ["BAZEL_BUILD"], |
||||||
|
deps = [ |
||||||
|
"//:grpc++", |
||||||
|
"//examples/protos:helloworld_cc_grpc", |
||||||
|
"@com_google_absl//absl/flags:flag", |
||||||
|
"@com_google_absl//absl/flags:parse", |
||||||
|
], |
||||||
|
) |
||||||
|
|
||||||
|
cc_binary( |
||||||
|
name = "greeter_callback_server_admin", |
||||||
|
srcs = ["greeter_callback_server_admin.cc"], |
||||||
|
defines = ["BAZEL_BUILD"], |
||||||
|
deps = [ |
||||||
|
"//:grpc++", |
||||||
|
"//:grpc++_reflection", |
||||||
|
"//:grpcpp_admin", |
||||||
|
"//examples/protos:helloworld_cc_grpc", |
||||||
|
"@com_google_absl//absl/flags:flag", |
||||||
|
"@com_google_absl//absl/flags:parse", |
||||||
|
"@com_google_absl//absl/strings:str_format", |
||||||
|
], |
||||||
|
) |
@ -0,0 +1,132 @@ |
|||||||
|
# gRPC C++ Debugging Example |
||||||
|
|
||||||
|
This example demonstrates a handful of ways you can debug your gRPC C++ applications. |
||||||
|
|
||||||
|
## Enabling Trace Logs |
||||||
|
|
||||||
|
gRPC allows you to configure more detailed log output for various aspects of gRPC behavior. The tracing log generation might have a large overhead and result in significantly larger log file sizes, especially when you try to trace transport or timer_check. But it is a powerful tool in your debugging toolkit. |
||||||
|
|
||||||
|
### The Most Verbose Logging |
||||||
|
|
||||||
|
Specify environment variables, then run your application: |
||||||
|
|
||||||
|
``` |
||||||
|
GRPC_VERBOSITY=debug |
||||||
|
GRPC_TRACE=all |
||||||
|
``` |
||||||
|
|
||||||
|
For more granularity, please see |
||||||
|
[environment_variables](https://github.com/grpc/grpc/blob/master/doc/environment_variables.md). |
||||||
|
|
||||||
|
### Debug Transport Protocol |
||||||
|
|
||||||
|
``` |
||||||
|
GRPC_VERBOSITY=debug |
||||||
|
GRPC_TRACE=tcp,http,secure_endpoint,transport_security |
||||||
|
``` |
||||||
|
|
||||||
|
### Debug Connection Behavior |
||||||
|
|
||||||
|
``` |
||||||
|
GRPC_VERBOSITY=debug |
||||||
|
GRPC_TRACE=call_error,connectivity_state,pick_first,round_robin,glb |
||||||
|
``` |
||||||
|
|
||||||
|
## GDB and other debuggers |
||||||
|
|
||||||
|
`gdb` (and the like) are tools that lets you inspect your application while it is running, view stack traces on exceptions, pause and step through code at specified points or under certain conditions, etc. See https://www.sourceware.org/gdb/ |
||||||
|
|
||||||
|
### Inspecting errors |
||||||
|
|
||||||
|
``` |
||||||
|
bazel build --config=dbg examples/cpp/debugging:crashing_greeter_client |
||||||
|
gdb -ex run \ |
||||||
|
--args ./bazel-bin/examples/cpp/debugging/crashing_greeter_client \ |
||||||
|
--crash_on_errors=true \ |
||||||
|
--target=localhork:50051 |
||||||
|
``` |
||||||
|
|
||||||
|
Once the exception is thrown, you can use `bt` to see the stack trace and examine the crash, `info threads` to get the set of threads, etc. See the [GDB documentation](https://sourceware.org/gdb/current/onlinedocs/gdb.html/) for a more complete list of available features and commands. |
||||||
|
|
||||||
|
### Breaking inside a function |
||||||
|
|
||||||
|
After building the application above, this will break inside gRPC generated stub code: |
||||||
|
|
||||||
|
``` |
||||||
|
gdb -ex 'b helloworld::Greeter::Stub::SayHello' \ |
||||||
|
-ex run \ |
||||||
|
--args ./bazel-bin/examples/cpp/debugging/crashing_greeter_client \ |
||||||
|
--crash_on_errors=true \ |
||||||
|
--target=localhork:50051 |
||||||
|
``` |
||||||
|
|
||||||
|
## gRPC Admin Interface: Live Channel Tracing |
||||||
|
|
||||||
|
The [gRPC Admin Service](https://github.com/grpc/proposal/blob/master/A38-admin-interface-api.md) |
||||||
|
provides a convenient API in each gRPC language to improve the usability of |
||||||
|
creating a gRPC server with admin services to expose states in the gRPC library. |
||||||
|
This includes channelz, which is a channel tracing feature; it tracks statistics |
||||||
|
like how many messages have been sent, how many of them failed, what are the |
||||||
|
connected sockets. See the [Channelz design doc](https://github.com/grpc/proposal/blob/master/A14-channelz.md). |
||||||
|
|
||||||
|
### Integrating the gRPC Admin Service Into Your Server |
||||||
|
|
||||||
|
As seen in the `greeter_callback_admin_server` target, you canenable admin services by using the `AddAdminServices` method. |
||||||
|
|
||||||
|
``` |
||||||
|
grpc::ServerBuilder builder; |
||||||
|
grpc::AddAdminServices(&builder); |
||||||
|
builder.AddListeningPort(":50051", grpc::ServerCredentials(...)); |
||||||
|
std::unique_ptr<grpc::Server> server(builder.BuildAndStart()); |
||||||
|
``` |
||||||
|
|
||||||
|
### Using grpcdebug |
||||||
|
|
||||||
|
grpcdebug is a tool created to access the metrics from channelz and health services. |
||||||
|
|
||||||
|
#### Installing the grpcdebug tool |
||||||
|
|
||||||
|
The source code is located in a github project |
||||||
|
[grpc-ecosystem/grpcdebug](https://github.com/grpc-ecosystem/grpcdebug). You |
||||||
|
can either download [the latest built version] |
||||||
|
(https://github.com/grpc-ecosystem/grpcdebug/releases/latest) (recommended) or |
||||||
|
follow the README.md to build it yourself. |
||||||
|
|
||||||
|
#### Running the grpcdebug tool |
||||||
|
##### Usage |
||||||
|
`grpcdebug <target address> [flags] channelz <command> [argument]` |
||||||
|
|
||||||
|
|
||||||
|
| Command | Argument | Description | |
||||||
|
| :--------- | :------------------: | :------------------------------------------------ | |
||||||
|
| channel | \<channel id or URL> | Display channel states in a human readable way. | |
||||||
|
| channels | | Lists client channels for the target application. | |
||||||
|
| server | \<server ID> | Displays server state in a human readable way. | |
||||||
|
| servers | | Lists servers in a human readable way. | |
||||||
|
| socket | \<socket ID> | Displays socket states in a human readable way. | |
||||||
|
| subchannel | \<id> | Display subchannel states in human readable way. | |
||||||
|
|
||||||
|
Generally, you will start with either `servers` or `channels` and then work down |
||||||
|
to the details |
||||||
|
|
||||||
|
##### Getting overall server info |
||||||
|
|
||||||
|
To begin with, build and run the server binary in the background |
||||||
|
|
||||||
|
``` |
||||||
|
bazel build --config=dbg examples/cpp/debugging:all |
||||||
|
./bazel-bin/examples/cpp/debugging/greeter_callback_server_admin& |
||||||
|
``` |
||||||
|
|
||||||
|
You can then inspect the server |
||||||
|
```bash |
||||||
|
grpcdebug localhost:50051 channelz servers |
||||||
|
``` |
||||||
|
|
||||||
|
This will show you the server ids with their activity |
||||||
|
```text |
||||||
|
Server ID Listen Addresses Calls(Started/Succeeded/Failed) Last Call Started |
||||||
|
1 [[::]:50051] 38/34/3 now |
||||||
|
``` |
||||||
|
|
||||||
|
For more information about `grpcdebug` features, please see [the grpcdebug documentation](https://github.com/grpc-ecosystem/grpcdebug) |
@ -0,0 +1,92 @@ |
|||||||
|
// 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.
|
||||||
|
|
||||||
|
#include <iostream> |
||||||
|
#include <memory> |
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include "absl/flags/flag.h" |
||||||
|
#include "absl/flags/parse.h" |
||||||
|
|
||||||
|
#include <grpcpp/grpcpp.h> |
||||||
|
|
||||||
|
#ifdef BAZEL_BUILD |
||||||
|
#include "examples/protos/helloworld.grpc.pb.h" |
||||||
|
#else |
||||||
|
#include "helloworld.grpc.pb.h" |
||||||
|
#endif |
||||||
|
|
||||||
|
ABSL_FLAG(bool, crash_on_errors, false, |
||||||
|
"Crash the application on client errors"); |
||||||
|
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> 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) { |
||||||
|
// Data we are sending to the server.
|
||||||
|
HelloRequest request; |
||||||
|
request.set_name(user); |
||||||
|
|
||||||
|
// Container for the data we expect from the server.
|
||||||
|
HelloReply reply; |
||||||
|
|
||||||
|
// Context for the client. It could be used to convey extra information to
|
||||||
|
// the server and/or tweak certain RPC behaviors.
|
||||||
|
ClientContext context; |
||||||
|
|
||||||
|
// The actual RPC.
|
||||||
|
Status status = stub_->SayHello(&context, request, &reply); |
||||||
|
|
||||||
|
// Act upon the status of the actual RPC.
|
||||||
|
if (absl::GetFlag(FLAGS_crash_on_errors)) { |
||||||
|
assert(status.ok()); |
||||||
|
} |
||||||
|
if (status.ok()) { |
||||||
|
return reply.message(); |
||||||
|
} else { |
||||||
|
return "RPC failed"; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
std::unique_ptr<Greeter::Stub> stub_; |
||||||
|
}; |
||||||
|
|
||||||
|
int main(int argc, char** argv) { |
||||||
|
absl::ParseCommandLine(argc, argv); |
||||||
|
// Instantiate the client. It requires a channel, out of which the actual RPCs
|
||||||
|
// are created. This channel models a connection to an endpoint specified by
|
||||||
|
// the argument "--target=" which is the only expected argument.
|
||||||
|
// We indicate that the channel isn't authenticated (use of
|
||||||
|
// InsecureChannelCredentials()).
|
||||||
|
GreeterClient greeter(grpc::CreateChannel( |
||||||
|
absl::GetFlag(FLAGS_target), grpc::InsecureChannelCredentials())); |
||||||
|
std::string user("world"); |
||||||
|
std::string reply = greeter.SayHello(user); |
||||||
|
std::cout << "Greeter received: " << reply << std::endl; |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
@ -0,0 +1,86 @@ |
|||||||
|
// 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.
|
||||||
|
|
||||||
|
#include <iostream> |
||||||
|
#include <memory> |
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include "absl/flags/flag.h" |
||||||
|
#include "absl/flags/parse.h" |
||||||
|
#include "absl/strings/str_format.h" |
||||||
|
|
||||||
|
#include <grpcpp/ext/admin_services.h> |
||||||
|
#include <grpcpp/ext/proto_server_reflection_plugin.h> |
||||||
|
#include <grpcpp/grpcpp.h> |
||||||
|
#include <grpcpp/health_check_service_interface.h> |
||||||
|
|
||||||
|
#ifdef BAZEL_BUILD |
||||||
|
#include "examples/protos/helloworld.grpc.pb.h" |
||||||
|
#else |
||||||
|
#include "helloworld.grpc.pb.h" |
||||||
|
#endif |
||||||
|
|
||||||
|
ABSL_FLAG(uint16_t, port, 50051, "Server port for the service"); |
||||||
|
|
||||||
|
using grpc::CallbackServerContext; |
||||||
|
using grpc::Server; |
||||||
|
using grpc::ServerBuilder; |
||||||
|
using grpc::ServerUnaryReactor; |
||||||
|
using grpc::Status; |
||||||
|
using helloworld::Greeter; |
||||||
|
using helloworld::HelloReply; |
||||||
|
using helloworld::HelloRequest; |
||||||
|
|
||||||
|
// Logic and data behind the server's behavior.
|
||||||
|
class GreeterServiceImpl final : public Greeter::CallbackService { |
||||||
|
ServerUnaryReactor* SayHello(CallbackServerContext* context, |
||||||
|
const HelloRequest* request, |
||||||
|
HelloReply* reply) override { |
||||||
|
std::string prefix("Hello "); |
||||||
|
reply->set_message(prefix + request->name()); |
||||||
|
|
||||||
|
ServerUnaryReactor* reactor = context->DefaultReactor(); |
||||||
|
reactor->Finish(Status::OK); |
||||||
|
return reactor; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
void RunServer(uint16_t port) { |
||||||
|
std::string server_address = absl::StrFormat("0.0.0.0:%d", port); |
||||||
|
GreeterServiceImpl service; |
||||||
|
|
||||||
|
grpc::EnableDefaultHealthCheckService(true); |
||||||
|
grpc::reflection::InitProtoReflectionServerBuilderPlugin(); |
||||||
|
ServerBuilder builder; |
||||||
|
// Enable gRPC Admin Services
|
||||||
|
grpc::AddAdminServices(&builder); |
||||||
|
// Listen on the given address without any authentication mechanism.
|
||||||
|
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); |
||||||
|
// Register "service" as the instance through which we'll communicate with
|
||||||
|
// clients. In this case it corresponds to an *synchronous* service.
|
||||||
|
builder.RegisterService(&service); |
||||||
|
// Finally assemble the server.
|
||||||
|
std::unique_ptr<Server> server(builder.BuildAndStart()); |
||||||
|
std::cout << "Server listening on " << server_address << std::endl; |
||||||
|
|
||||||
|
// Wait for the server to shutdown. Note that some other thread must be
|
||||||
|
// responsible for shutting down the server for this call to ever return.
|
||||||
|
server->Wait(); |
||||||
|
} |
||||||
|
|
||||||
|
int main(int argc, char** argv) { |
||||||
|
absl::ParseCommandLine(argc, argv); |
||||||
|
RunServer(absl::GetFlag(FLAGS_port)); |
||||||
|
return 0; |
||||||
|
} |
@ -0,0 +1,29 @@ |
|||||||
|
# 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 = "orca_server", |
||||||
|
srcs = ["orca_server.cc"], |
||||||
|
defines = ["BAZEL_BUILD"], |
||||||
|
deps = [ |
||||||
|
"//:grpc++", |
||||||
|
"//:grpcpp_orca_service", |
||||||
|
"//examples/protos:helloworld_cc_grpc", |
||||||
|
"@com_google_absl//absl/flags:flag", |
||||||
|
"@com_google_absl//absl/flags:parse", |
||||||
|
"@com_google_absl//absl/strings:str_format", |
||||||
|
], |
||||||
|
) |
@ -0,0 +1,46 @@ |
|||||||
|
# gRPC Custom Metrics Example |
||||||
|
|
||||||
|
You can find a complete set of instructions for building gRPC and running the |
||||||
|
examples in the [C++ Quick Start][]. |
||||||
|
|
||||||
|
This example shows how to implement a server that provides custom metrics usable |
||||||
|
by custom load balancing policies. |
||||||
|
|
||||||
|
Server needs to be setup with metrics recorder and Orca service for sending |
||||||
|
these metrics to a client: |
||||||
|
|
||||||
|
```c++ |
||||||
|
GreeterServiceImpl service; |
||||||
|
// Setup custom metrics recording |
||||||
|
auto server_metric_recorder = |
||||||
|
grpc::experimental::ServerMetricRecorder::Create(); |
||||||
|
grpc::experimental::OrcaService orca_service( |
||||||
|
server_metric_recorder.get(), |
||||||
|
grpc::experimental::OrcaService::Options().set_min_report_duration( |
||||||
|
absl::Seconds(0.1))); |
||||||
|
builder.RegisterService(&orca_service); |
||||||
|
grpc::ServerBuilder::experimental_type(&builder).EnableCallMetricRecording( |
||||||
|
nullptr); |
||||||
|
``` |
||||||
|
|
||||||
|
Afterwards per-request metrics can be reported from the gRPC service |
||||||
|
implementation using the metric recorder from the request context: |
||||||
|
|
||||||
|
```c++ |
||||||
|
auto recorder = context->ExperimentalGetCallMetricRecorder(); |
||||||
|
if (recorder == nullptr) { |
||||||
|
return Status(grpc::StatusCode::INTERNAL, |
||||||
|
"Unable to access metrics recorder. Make sure " |
||||||
|
"EnableCallMetricRecording had been called."); |
||||||
|
} |
||||||
|
recorder->RecordCpuUtilizationMetric(0.5); |
||||||
|
``` |
||||||
|
|
||||||
|
Out of band metrics can be reported using the `server_metric_recorder` |
||||||
|
directly: |
||||||
|
|
||||||
|
```c++ |
||||||
|
server_metric_recorder->SetCpuUtilization(0.75); |
||||||
|
``` |
||||||
|
|
||||||
|
[C++ Quick Start]: https://grpc.io/docs/languages/cpp/quickstart |
@ -0,0 +1,101 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* 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 <cstddef> |
||||||
|
#include <iostream> |
||||||
|
#include <memory> |
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include "absl/flags/flag.h" |
||||||
|
#include "absl/flags/parse.h" |
||||||
|
#include "absl/strings/str_format.h" |
||||||
|
#include "examples/protos/helloworld.grpc.pb.h" |
||||||
|
|
||||||
|
#include <grpcpp/ext/call_metric_recorder.h> |
||||||
|
#include <grpcpp/ext/orca_service.h> |
||||||
|
#include <grpcpp/grpcpp.h> |
||||||
|
#include <grpcpp/health_check_service_interface.h> |
||||||
|
#include <grpcpp/support/status.h> |
||||||
|
|
||||||
|
using grpc::CallbackServerContext; |
||||||
|
using grpc::Server; |
||||||
|
using grpc::ServerBuilder; |
||||||
|
using grpc::ServerUnaryReactor; |
||||||
|
using grpc::Status; |
||||||
|
using helloworld::Greeter; |
||||||
|
using helloworld::HelloReply; |
||||||
|
using helloworld::HelloRequest; |
||||||
|
|
||||||
|
ABSL_FLAG(uint16_t, port, 50051, "Server port for the service"); |
||||||
|
|
||||||
|
// Logic and data behind the server's behavior.
|
||||||
|
class GreeterServiceImpl final : public Greeter::CallbackService { |
||||||
|
ServerUnaryReactor* SayHello(CallbackServerContext* context, |
||||||
|
const HelloRequest* request, |
||||||
|
HelloReply* reply) override { |
||||||
|
ServerUnaryReactor* reactor = context->DefaultReactor(); |
||||||
|
// Obtain the call metric recorder and use it to report the number of
|
||||||
|
// DB queries (custom cost metric) and CPU utilization.
|
||||||
|
auto recorder = context->ExperimentalGetCallMetricRecorder(); |
||||||
|
if (recorder == nullptr) { |
||||||
|
reactor->Finish({grpc::StatusCode::INTERNAL, |
||||||
|
"Unable to access metrics recorder. Make sure " |
||||||
|
"EnableCallMetricRecording had been called."}); |
||||||
|
return reactor; |
||||||
|
} |
||||||
|
recorder->RecordRequestCostMetric("db_queries", 10); |
||||||
|
recorder->RecordCpuUtilizationMetric(0.5); |
||||||
|
std::string prefix("Hello "); |
||||||
|
reply->set_message(prefix + request->name()); |
||||||
|
reactor->Finish(Status::OK); |
||||||
|
return reactor; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
void RunServer(uint16_t port) { |
||||||
|
std::string server_address = absl::StrFormat("0.0.0.0:%d", port); |
||||||
|
ServerBuilder builder; |
||||||
|
GreeterServiceImpl service; |
||||||
|
// Setup custom metrics recording. Note that this recorder may be use to send
|
||||||
|
// the out-of-band metrics to the client.
|
||||||
|
auto server_metric_recorder = |
||||||
|
grpc::experimental::ServerMetricRecorder::Create(); |
||||||
|
grpc::experimental::OrcaService orca_service( |
||||||
|
server_metric_recorder.get(), |
||||||
|
grpc::experimental::OrcaService::Options().set_min_report_duration( |
||||||
|
absl::Seconds(0.1))); |
||||||
|
builder.RegisterService(&orca_service); |
||||||
|
grpc::ServerBuilder::experimental_type(&builder).EnableCallMetricRecording( |
||||||
|
server_metric_recorder.get()); |
||||||
|
// Resume setting up gRPC server as usual
|
||||||
|
grpc::EnableDefaultHealthCheckService(true); |
||||||
|
// Listen on the given address without any authentication mechanism.
|
||||||
|
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); |
||||||
|
// Register "service" as the instance through which we'll communicate with
|
||||||
|
// clients. In this case it corresponds to an *synchronous* service.
|
||||||
|
builder.RegisterService(&service); |
||||||
|
// Finally assemble the server.
|
||||||
|
std::unique_ptr<Server> server(builder.BuildAndStart()); |
||||||
|
std::cout << "Server listening on " << server_address << std::endl; |
||||||
|
server->Wait(); |
||||||
|
} |
||||||
|
|
||||||
|
int main(int argc, char** argv) { |
||||||
|
absl::ParseCommandLine(argc, argv); |
||||||
|
RunServer(absl::GetFlag(FLAGS_port)); |
||||||
|
return 0; |
||||||
|
} |
@ -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", |
||||||
|
], |
||||||
|
) |
@ -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() |
@ -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. |
@ -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 <condition_variable> |
||||||
|
#include <iostream> |
||||||
|
#include <memory> |
||||||
|
#include <mutex> |
||||||
|
#include <string> |
||||||
|
#include <thread> |
||||||
|
|
||||||
|
#include "absl/flags/flag.h" |
||||||
|
#include "absl/flags/parse.h" |
||||||
|
|
||||||
|
#include <grpcpp/grpcpp.h> |
||||||
|
|
||||||
|
#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> 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<std::mutex> lock(mu); |
||||||
|
done = true; |
||||||
|
cv.notify_one(); |
||||||
|
}); |
||||||
|
|
||||||
|
std::unique_lock<std::mutex> 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<Greeter::Stub> 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; |
||||||
|
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue