Merge branch 'master' into revert-18502-revert-18242-grpc_namespace_serverbuilder

pull/18510/head
Karthik Ravi Shankar 6 years ago
commit 29c0aacfc0
  1. 36
      BUILD
  2. 24
      bazel/grpc_build_system.bzl
  3. 119
      examples/BUILD
  4. 4
      examples/cpp/helloworld/greeter_async_client.cc
  5. 4
      examples/cpp/helloworld/greeter_async_client2.cc
  6. 4
      examples/cpp/helloworld/greeter_async_server.cc
  7. 31
      examples/cpp/route_guide/helper.cc
  8. 4
      examples/cpp/route_guide/route_guide_client.cc
  9. 4
      examples/cpp/route_guide/route_guide_server.cc
  10. 56
      examples/python/errors/BUILD.bazel
  11. 107
      examples/python/errors/README.md
  12. 56
      examples/python/errors/client.py
  13. 90
      examples/python/errors/server.py
  14. 54
      examples/python/errors/test/_error_handling_example_test.py
  15. 16
      include/grpcpp/impl/codegen/server_callback.h
  16. 230
      src/core/ext/filters/client_channel/client_channel.cc
  17. 7
      src/core/ext/filters/client_channel/lb_policy.cc
  18. 11
      src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
  19. 2
      src/core/lib/gprpp/fork.cc
  20. 27
      src/core/lib/iomgr/cfstream_handle.cc
  21. 10
      src/core/lib/iomgr/tcp_client_windows.cc
  22. 7
      src/cpp/client/channel_cc.cc
  23. 6
      src/csharp/Grpc.Core/Channel.cs
  24. 50
      src/php/ext/grpc/php_grpc.c
  25. 2
      src/php/ext/grpc/php_grpc.h
  26. 15
      src/php/ext/grpc/tests/grpc-default-ini.phpt
  27. 24
      src/php/ext/grpc/tests/grpc-set-ini.phpt
  28. 1
      src/python/grpcio_tests/tests/BUILD.bazel
  29. 1
      test/core/bad_connection/BUILD
  30. 1
      test/core/client_channel/BUILD
  31. 11
      test/core/end2end/generate_tests.bzl
  32. 10
      test/core/iomgr/BUILD
  33. 1
      test/cpp/common/BUILD
  34. 2
      test/cpp/end2end/BUILD
  35. 150
      test/cpp/end2end/cfstream_test.cc
  36. 1
      test/cpp/end2end/test_service_impl.cc
  37. 1
      test/cpp/interop/BUILD
  38. 18
      test/cpp/microbenchmarks/BUILD
  39. 5
      test/cpp/naming/generate_resolver_component_tests.bzl
  40. 1
      test/cpp/performance/BUILD
  41. 1
      test/cpp/qps/qps_benchmark_script.bzl
  42. 3
      test/cpp/server/BUILD
  43. 1
      test/cpp/server/load_reporter/BUILD
  44. 15
      test/cpp/util/proto_reflection_descriptor_database.cc
  45. 8
      tools/remote_build/README.md
  46. 3
      tools/remote_build/windows.bazelrc

36
BUILD

@ -362,10 +362,10 @@ grpc_cc_library(
"gpr",
"grpc",
"grpc++_base",
"grpc_cfstream",
"grpc++_codegen_base",
"grpc++_codegen_base_src",
"grpc++_codegen_proto",
"grpc_cfstream",
],
)
@ -2318,34 +2318,34 @@ grpc_cc_library(
name = "envoy_ads_upb",
srcs = [
"src/core/ext/upb-generated/envoy/api/v2/auth/cert.upb.c",
"src/core/ext/upb-generated/envoy/api/v2/cds.upb.c",
"src/core/ext/upb-generated/envoy/api/v2/cluster/circuit_breaker.upb.c",
"src/core/ext/upb-generated/envoy/api/v2/cluster/outlier_detection.upb.c",
"src/core/ext/upb-generated/envoy/api/v2/discovery.upb.c",
"src/core/ext/upb-generated/envoy/api/v2/endpoint/endpoint.upb.c",
"src/core/ext/upb-generated/envoy/api/v2/cds.upb.c",
"src/core/ext/upb-generated/envoy/api/v2/eds.upb.c",
"src/core/ext/upb-generated/envoy/api/v2/endpoint/endpoint.upb.c",
"src/core/ext/upb-generated/envoy/service/discovery/v2/ads.upb.c",
],
hdrs = [
"src/core/ext/upb-generated/envoy/api/v2/auth/cert.upb.h",
"src/core/ext/upb-generated/envoy/api/v2/cds.upb.h",
"src/core/ext/upb-generated/envoy/api/v2/cluster/circuit_breaker.upb.h",
"src/core/ext/upb-generated/envoy/api/v2/cluster/outlier_detection.upb.h",
"src/core/ext/upb-generated/envoy/api/v2/discovery.upb.h",
"src/core/ext/upb-generated/envoy/api/v2/endpoint/endpoint.upb.h",
"src/core/ext/upb-generated/envoy/api/v2/cds.upb.h",
"src/core/ext/upb-generated/envoy/api/v2/eds.upb.h",
"src/core/ext/upb-generated/envoy/api/v2/endpoint/endpoint.upb.h",
"src/core/ext/upb-generated/envoy/service/discovery/v2/ads.upb.h",
],
language = "c++",
external_deps = [
"upb_lib",
],
language = "c++",
deps = [
":envoy_core_upb",
":envoy_type_upb",
":google_api_upb",
":proto_gen_validate_upb",
]
],
)
grpc_cc_library(
@ -2366,15 +2366,16 @@ grpc_cc_library(
"src/core/ext/upb-generated/envoy/api/v2/core/health_check.upb.h",
"src/core/ext/upb-generated/envoy/api/v2/core/protocol.upb.h",
],
language = "c++",
external_deps = [
"upb_lib",
],
language = "c++",
tags = ["no_windows"],
deps = [
":envoy_type_upb",
":google_api_upb",
":proto_gen_validate_upb"
]
":proto_gen_validate_upb",
],
)
grpc_cc_library(
@ -2387,14 +2388,15 @@ grpc_cc_library(
"src/core/ext/upb-generated/envoy/type/percent.upb.h",
"src/core/ext/upb-generated/envoy/type/range.upb.h",
],
language = "c++",
external_deps = [
"upb_lib",
],
language = "c++",
tags = ["no_windows"],
deps = [
":google_api_upb",
":proto_gen_validate_upb"
]
":proto_gen_validate_upb",
],
)
grpc_cc_library(
@ -2407,13 +2409,14 @@ grpc_cc_library(
"src/core/ext/upb-generated/gogoproto/gogo.upb.h",
"src/core/ext/upb-generated/validate/validate.upb.h",
],
language = "c++",
external_deps = [
"upb_lib",
],
language = "c++",
tags = ["no_windows"],
deps = [
":google_api_upb",
]
],
)
grpc_cc_library(
@ -2442,10 +2445,11 @@ grpc_cc_library(
"src/core/ext/upb-generated/google/protobuf/wrappers.upb.h",
"src/core/ext/upb-generated/google/rpc/status.upb.h",
],
language = "c++",
external_deps = [
"upb_lib",
],
language = "c++",
tags = ["no_windows"],
)
grpc_generate_one_off_targets()

@ -80,7 +80,8 @@ def grpc_cc_library(
visibility = None,
alwayslink = 0,
data = [],
use_cfstream = False):
use_cfstream = False,
tags = []):
copts = []
if use_cfstream:
copts = if_mac(["-DGRPC_CFSTREAM"])
@ -117,6 +118,7 @@ def grpc_cc_library(
],
alwayslink = alwayslink,
data = data,
tags = tags,
)
def grpc_proto_plugin(name, srcs = [], deps = []):
@ -149,7 +151,6 @@ def grpc_cc_test(name, srcs = [], deps = [], external_deps = [], args = [], data
if language.upper() == "C":
copts = copts + if_not_windows(["-std=c99"])
args = {
"name": name,
"srcs": srcs,
"args": args,
"data": data,
@ -161,7 +162,17 @@ def grpc_cc_test(name, srcs = [], deps = [], external_deps = [], args = [], data
"exec_compatible_with": exec_compatible_with,
}
if uses_polling:
native.cc_test(testonly = True, tags = ["manual"], **args)
# Only run targets with pollers for non-MSVC
# TODO(yfen): Enable MSVC for poller-enabled targets without pollers
native.cc_test(
name = name,
testonly = True,
tags = [
"manual",
"no_windows",
],
**args
)
for poller in POLLERS:
native.sh_test(
name = name + "@poller=" + poller,
@ -175,13 +186,13 @@ def grpc_cc_test(name, srcs = [], deps = [], external_deps = [], args = [], data
poller,
"$(location %s)" % name,
] + args["args"],
tags = tags,
tags = (tags + ["no_windows"]),
exec_compatible_with = exec_compatible_with,
)
else:
native.cc_test(**args)
native.cc_test(tags = tags, **args)
def grpc_cc_binary(name, srcs = [], deps = [], external_deps = [], args = [], data = [], language = "C++", testonly = False, linkshared = False, linkopts = []):
def grpc_cc_binary(name, srcs = [], deps = [], external_deps = [], args = [], data = [], language = "C++", testonly = False, linkshared = False, linkopts = [], tags = []):
copts = []
if language.upper() == "C":
copts = ["-std=c99"]
@ -195,6 +206,7 @@ def grpc_cc_binary(name, srcs = [], deps = [], external_deps = [], args = [], da
deps = deps + _get_external_deps(external_deps),
copts = copts,
linkopts = if_not_windows(["-pthread"]) + linkopts,
tags = tags,
)
def grpc_generate_one_off_targets():

@ -16,7 +16,9 @@ licenses(["notice"]) # 3-clause BSD
package(default_visibility = ["//visibility:public"])
load("@grpc_python_dependencies//:requirements.bzl", "requirement")
load("//bazel:grpc_build_system.bzl", "grpc_proto_library")
load("@org_pubref_rules_protobuf//python:rules.bzl", "py_proto_library")
grpc_proto_library(
name = "auth_sample",
@ -43,60 +45,121 @@ grpc_proto_library(
srcs = ["protos/keyvaluestore.proto"],
)
py_proto_library(
name = "py_helloworld",
protos = ["protos/helloworld.proto"],
with_grpc = True,
deps = [requirement('protobuf'),],
)
cc_binary(
name = "greeter_client",
srcs = ["cpp/helloworld/greeter_client.cc"],
defines = ["BAZEL_BUILD"],
deps = [":helloworld", "//:grpc++"],
deps = [
":helloworld",
"//:grpc++",
],
)
cc_binary(
name = "greeter_async_client",
srcs = ["cpp/helloworld/greeter_async_client.cc"],
defines = ["BAZEL_BUILD"],
deps = [
":helloworld",
"//:grpc++",
],
)
cc_binary(
name = "greeter_async_client2",
srcs = ["cpp/helloworld/greeter_async_client2.cc"],
defines = ["BAZEL_BUILD"],
deps = [
":helloworld",
"//:grpc++",
],
)
cc_binary(
name = "greeter_server",
srcs = ["cpp/helloworld/greeter_server.cc"],
defines = ["BAZEL_BUILD"],
deps = [":helloworld", "//:grpc++"],
deps = [
":helloworld",
"//:grpc++",
],
)
cc_binary(
name = "greeter_async_server",
srcs = ["cpp/helloworld/greeter_async_server.cc"],
defines = ["BAZEL_BUILD"],
deps = [
":helloworld",
"//:grpc++",
],
)
cc_binary(
name = "metadata_client",
srcs = ["cpp/metadata/greeter_client.cc"],
defines = ["BAZEL_BUILD"],
deps = [":helloworld", "//:grpc++"],
deps = [
":helloworld",
"//:grpc++",
],
)
cc_binary(
name = "metadata_server",
srcs = ["cpp/metadata/greeter_server.cc"],
defines = ["BAZEL_BUILD"],
deps = [":helloworld", "//:grpc++"],
deps = [
":helloworld",
"//:grpc++",
],
)
cc_binary(
name = "lb_client",
srcs = ["cpp/load_balancing/greeter_client.cc"],
defines = ["BAZEL_BUILD"],
deps = [":helloworld", "//:grpc++"],
deps = [
":helloworld",
"//:grpc++",
],
)
cc_binary(
name = "lb_server",
srcs = ["cpp/load_balancing/greeter_server.cc"],
defines = ["BAZEL_BUILD"],
deps = [":helloworld", "//:grpc++"],
deps = [
":helloworld",
"//:grpc++",
],
)
cc_binary(
name = "compression_client",
srcs = ["cpp/compression/greeter_client.cc"],
defines = ["BAZEL_BUILD"],
deps = [":helloworld", "//:grpc++"],
deps = [
":helloworld",
"//:grpc++",
],
)
cc_binary(
name = "compression_server",
srcs = ["cpp/compression/greeter_server.cc"],
defines = ["BAZEL_BUILD"],
deps = [":helloworld", "//:grpc++"],
deps = [
":helloworld",
"//:grpc++",
],
)
cc_binary(
@ -104,12 +167,48 @@ cc_binary(
srcs = ["cpp/keyvaluestore/caching_interceptor.h",
"cpp/keyvaluestore/client.cc"],
defines = ["BAZEL_BUILD"],
deps = [":keyvaluestore", "//:grpc++"],
deps = [
":keyvaluestore",
"//:grpc++",
],
)
cc_binary(
name = "keyvaluestore_server",
srcs = ["cpp/keyvaluestore/server.cc"],
defines = ["BAZEL_BUILD"],
deps = [":keyvaluestore", "//:grpc++"],
deps = [
":keyvaluestore",
"//:grpc++",
],
)
cc_binary(
name = "route_guide_client",
srcs = [
"cpp/route_guide/helper.cc",
"cpp/route_guide/helper.h",
"cpp/route_guide/route_guide_client.cc",
],
data = ["cpp/route_guide/route_guide_db.json"],
defines = ["BAZEL_BUILD"],
deps = [
":route_guide",
"//:grpc++",
],
)
cc_binary(
name = "route_guide_server",
srcs = [
"cpp/route_guide/helper.cc",
"cpp/route_guide/helper.h",
"cpp/route_guide/route_guide_server.cc",
],
data = ["cpp/route_guide/route_guide_db.json"],
defines = ["BAZEL_BUILD"],
deps = [
":route_guide",
"//:grpc++",
],
)

@ -23,7 +23,11 @@
#include <grpcpp/grpcpp.h>
#include <grpc/support/log.h>
#ifdef BAZEL_BUILD
#include "examples/protos/helloworld.grpc.pb.h"
#else
#include "helloworld.grpc.pb.h"
#endif
using grpc::Channel;
using grpc::ClientAsyncResponseReader;

@ -24,7 +24,11 @@
#include <grpc/support/log.h>
#include <thread>
#ifdef BAZEL_BUILD
#include "examples/protos/helloworld.grpc.pb.h"
#else
#include "helloworld.grpc.pb.h"
#endif
using grpc::Channel;
using grpc::ClientAsyncResponseReader;

@ -24,7 +24,11 @@
#include <grpcpp/grpcpp.h>
#include <grpc/support/log.h>
#ifdef BAZEL_BUILD
#include "examples/protos/helloworld.grpc.pb.h"
#else
#include "helloworld.grpc.pb.h"
#endif
using grpc::Server;
using grpc::ServerAsyncResponseWriter;

@ -23,7 +23,11 @@
#include <sstream>
#include <string>
#include <vector>
#ifdef BAZEL_BUILD
#include "examples/protos/route_guide.grpc.pb.h"
#else
#include "route_guide.grpc.pb.h"
#endif
namespace routeguide {
@ -35,13 +39,16 @@ std::string GetDbFileContent(int argc, char** argv) {
size_t start_position = argv_1.find(arg_str);
if (start_position != std::string::npos) {
start_position += arg_str.size();
if (argv_1[start_position] == ' ' ||
argv_1[start_position] == '=') {
if (argv_1[start_position] == ' ' || argv_1[start_position] == '=') {
db_path = argv_1.substr(start_position + 1);
}
}
} else {
#ifdef BAZEL_BUILD
db_path = "cpp/route_guide/route_guide_db.json";
#else
db_path = "route_guide_db.json";
#endif
}
std::ifstream db_file(db_path);
if (!db_file.is_open()) {
@ -60,17 +67,13 @@ class Parser {
public:
explicit Parser(const std::string& db) : db_(db) {
// Remove all spaces.
db_.erase(
std::remove_if(db_.begin(), db_.end(), isspace),
db_.end());
db_.erase(std::remove_if(db_.begin(), db_.end(), isspace), db_.end());
if (!Match("[")) {
SetFailedAndReturnFalse();
}
}
bool Finished() {
return current_ >= db_.size();
}
bool Finished() { return current_ >= db_.size(); }
bool TryParseOne(Feature* feature) {
if (failed_ || Finished() || !Match("{")) {
@ -96,7 +99,7 @@ class Parser {
if (current_ == db_.size()) {
return SetFailedAndReturnFalse();
}
feature->set_name(db_.substr(name_start, current_-name_start-1));
feature->set_name(db_.substr(name_start, current_ - name_start - 1));
if (!Match("},")) {
if (db_[current_ - 1] == ']' && current_ == db_.size()) {
return true;
@ -107,7 +110,6 @@ class Parser {
}
private:
bool SetFailedAndReturnFalse() {
failed_ = true;
return false;
@ -121,7 +123,8 @@ class Parser {
void ReadLong(long* l) {
size_t start = current_;
while (current_ != db_.size() && db_[current_] != ',' && db_[current_] != '}') {
while (current_ != db_.size() && db_[current_] != ',' &&
db_[current_] != '}') {
current_++;
}
// It will throw an exception if fails.
@ -154,10 +157,8 @@ void ParseDb(const std::string& db, std::vector<Feature>* feature_list) {
break;
}
}
std::cout << "DB parsed, loaded " << feature_list->size()
<< " features." << std::endl;
std::cout << "DB parsed, loaded " << feature_list->size() << " features."
<< std::endl;
}
} // namespace routeguide

@ -29,7 +29,11 @@
#include <grpcpp/create_channel.h>
#include <grpcpp/security/credentials.h>
#include "helper.h"
#ifdef BAZEL_BUILD
#include "examples/protos/route_guide.grpc.pb.h"
#else
#include "route_guide.grpc.pb.h"
#endif
using grpc::Channel;
using grpc::ClientContext;

@ -29,7 +29,11 @@
#include <grpcpp/server_context.h>
#include <grpcpp/security/server_credentials.h>
#include "helper.h"
#ifdef BAZEL_BUILD
#include "examples/protos/route_guide.grpc.pb.h"
#else
#include "route_guide.grpc.pb.h"
#endif
using grpc::Server;
using grpc::ServerBuilder;

@ -0,0 +1,56 @@
# Copyright 2019 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.
load("@grpc_python_dependencies//:requirements.bzl", "requirement")
py_library(
name = "client",
testonly = 1,
srcs = ["client.py"],
deps = [
"//src/python/grpcio/grpc:grpcio",
"//src/python/grpcio_status/grpc_status:grpc_status",
"//examples:py_helloworld",
requirement('googleapis-common-protos'),
],
)
py_library(
name = "server",
testonly = 1,
srcs = ["server.py"],
deps = [
"//src/python/grpcio/grpc:grpcio",
"//src/python/grpcio_status/grpc_status:grpc_status",
"//examples:py_helloworld",
] + select({
"//conditions:default": [requirement("futures")],
"//:python3": [],
}),
)
py_test(
name = "test/_error_handling_example_test",
srcs = ["test/_error_handling_example_test.py"],
deps = [
":client",
":server",
"//src/python/grpcio_tests/tests:bazel_namespace_package_hack",
],
size = "small",
imports = [
"../../../src/python/grpcio_status",
"../../../src/python/grpcio_tests",
],
)

@ -0,0 +1,107 @@
# gRPC Python Error Handling Example
The goal of this example is sending error status from server that is more complicated than a code and detail string.
The definition for an RPC method in proto files contains request message and response message. There are many error states that can be shared across RPC methods (e.g. stack trace, insufficient quota). Using a different path to handle error will make the code more maintainable.
Ideally, the final status of an RPC should be described in the trailing headers of HTTP2, and gRPC Python provides helper functions in `grpcio-status` package to assist the packing and unpacking of error status.
### Requirement
```
grpcio>=1.18.0
grpcio-status>=1.18.0
googleapis-common-protos>=1.5.5
```
### Error Detail Proto
You may provide any custom proto message as error detail in your implementation. Here are protos are defined by Google Cloud Library Team:
* [code.proto]([https://github.com/googleapis/api-common-protos/blob/master/google/rpc/code.proto](https://github.com/googleapis/api-common-protos/blob/87185dfffad4afa5a33a8c153f0e1ea53b4f85dc/google/rpc/code.proto)) contains definition of RPC error codes.
* [error_details.proto]([https://github.com/googleapis/api-common-protos/blob/master/google/rpc/error_details.proto](https://github.com/googleapis/api-common-protos/blob/87185dfffad4afa5a33a8c153f0e1ea53b4f85dc/google/rpc/error_details.proto)) contains definitions of common error details.
### Definition of Status Proto
Here is the definition of Status proto. For full text, please see [status.proto](https://github.com/googleapis/api-common-protos/blob/87185dfffad4afa5a33a8c153f0e1ea53b4f85dc/google/rpc/status.proto).
```proto
// The `Status` type defines a logical error model that is suitable for different
// programming environments, including REST APIs and RPC APIs. It is used by
// [gRPC](https://github.com/grpc). The error model is designed to be:
//
// - Simple to use and understand for most users
// - Flexible enough to meet unexpected needs
//
// # Overview
//
// The `Status` message contains three pieces of data: error code, error message,
// and error details. The error code should be an enum value of
// [google.rpc.Code][google.rpc.Code], but it may accept additional error codes if needed. The
// error message should be a developer-facing English message that helps
// developers *understand* and *resolve* the error. If a localized user-facing
// error message is needed, put the localized message in the error details or
// localize it in the client. The optional error details may contain arbitrary
// information about the error. There is a predefined set of error detail types
// in the package `google.rpc` that can be used for common error conditions.
//
// # Language mapping
//
// The `Status` message is the logical representation of the error model, but it
// is not necessarily the actual wire format. When the `Status` message is
// exposed in different client libraries and different wire protocols, it can be
// mapped differently. For example, it will likely be mapped to some exceptions
// in Java, but more likely mapped to some error codes in C.
//
// # Other uses
//
// The error model and the `Status` message can be used in a variety of
// environments, either with or without APIs, to provide a
// consistent developer experience across different environments.
//
// Example uses of this error model include:
//
// - Partial errors. If a service needs to return partial errors to the client,
// it may embed the `Status` in the normal response to indicate the partial
// errors.
//
// - Workflow errors. A typical workflow has multiple steps. Each step may
// have a `Status` message for error reporting.
//
// - Batch operations. If a client uses batch request and batch response, the
// `Status` message should be used directly inside batch response, one for
// each error sub-response.
//
// - Asynchronous operations. If an API call embeds asynchronous operation
// results in its response, the status of those operations should be
// represented directly using the `Status` message.
//
// - Logging. If some API errors are stored in logs, the message `Status` could
// be used directly after any stripping needed for security/privacy reasons.
message Status {
// The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code].
int32 code = 1;
// A developer-facing error message, which should be in English. Any
// user-facing error message should be localized and sent in the
// [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client.
string message = 2;
// A list of messages that carry the error details. There is a common set of
// message types for APIs to use.
repeated google.protobuf.Any details = 3;
}
```
### Usage of Well-Known-Proto `Any`
Please check [ProtoBuf Document: Any](https://developers.google.com/protocol-buffers/docs/reference/python-generated#any)
```Python
any_message.Pack(message)
any_message.Unpack(message)
assert any_message.Is(message.DESCRIPTOR)
```

@ -0,0 +1,56 @@
# Copyright 2019 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.
"""This example handles rich error status in client-side."""
from __future__ import print_function
import logging
import grpc
from grpc_status import rpc_status
from google.rpc import error_details_pb2
from examples.protos import helloworld_pb2
from examples.protos import helloworld_pb2_grpc
_LOGGER = logging.getLogger(__name__)
def process(stub):
try:
response = stub.SayHello(helloworld_pb2.HelloRequest(name='Alice'))
_LOGGER.info('Call success: %s', response.message)
except grpc.RpcError as rpc_error:
_LOGGER.error('Call failure: %s', rpc_error)
status = rpc_status.from_call(rpc_error)
for detail in status.details:
if detail.Is(error_details_pb2.QuotaFailure.DESCRIPTOR):
info = error_details_pb2.QuotaFailure()
detail.Unpack(info)
_LOGGER.error('Quota failure: %s', info)
else:
raise RuntimeError('Unexpected failure: %s' % detail)
def main():
# NOTE(gRPC Python Team): .close() is possible on a channel and should be
# used in circumstances in which the with statement does not fit the needs
# of the code.
with grpc.insecure_channel('localhost:50051') as channel:
stub = helloworld_pb2_grpc.GreeterStub(channel)
process(stub)
if __name__ == '__main__':
logging.basicConfig()
main()

@ -0,0 +1,90 @@
# Copyright 2019 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.
"""This example sends out rich error status from server-side."""
from concurrent import futures
import time
import logging
import threading
import grpc
from grpc_status import rpc_status
from google.protobuf import any_pb2
from google.rpc import code_pb2, status_pb2, error_details_pb2
from examples.protos import helloworld_pb2
from examples.protos import helloworld_pb2_grpc
_ONE_DAY_IN_SECONDS = 60 * 60 * 24
def create_greet_limit_exceed_error_status(name):
detail = any_pb2.Any()
detail.Pack(
error_details_pb2.QuotaFailure(
violations=[
error_details_pb2.QuotaFailure.Violation(
subject="name: %s" % name,
description="Limit one greeting per person",
)
],))
return status_pb2.Status(
code=code_pb2.RESOURCE_EXHAUSTED,
message='Request limit exceeded.',
details=[detail],
)
class LimitedGreeter(helloworld_pb2_grpc.GreeterServicer):
def __init__(self):
self._lock = threading.RLock()
self._greeted = set()
def SayHello(self, request, context):
with self._lock:
if request.name in self._greeted:
rich_status = create_greet_limit_exceed_error_status(
request.name)
context.abort_with_status(rpc_status.to_status(rich_status))
else:
self._greeted.add(request.name)
return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name)
def create_server(server_address):
server = grpc.server(futures.ThreadPoolExecutor())
helloworld_pb2_grpc.add_GreeterServicer_to_server(LimitedGreeter(), server)
port = server.add_insecure_port(server_address)
return server, port
def serve(server):
server.start()
try:
while True:
time.sleep(_ONE_DAY_IN_SECONDS)
except KeyboardInterrupt:
server.stop(None)
def main():
server, unused_port = create_server('[::]:50051')
serve(server)
if __name__ == '__main__':
logging.basicConfig()
main()

@ -0,0 +1,54 @@
# Copyright 2019 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.
"""Tests of the error handling example."""
# NOTE(lidiz) This module only exists in Bazel BUILD file, for more details
# please refer to comments in the "bazel_namespace_package_hack" module.
try:
from tests import bazel_namespace_package_hack
bazel_namespace_package_hack.sys_path_to_site_dir_hack()
except ImportError:
pass
import unittest
import logging
import grpc
from examples.protos import helloworld_pb2_grpc
from examples.python.errors import client as error_handling_client
from examples.python.errors import server as error_handling_server
class ErrorHandlingExampleTest(unittest.TestCase):
def setUp(self):
self._server, port = error_handling_server.create_server('[::]:0')
self._server.start()
self._channel = grpc.insecure_channel('localhost:%d' % port)
def tearDown(self):
self._channel.close()
self._server.stop(None)
def test_error_handling_example(self):
stub = helloworld_pb2_grpc.GreeterStub(self._channel)
error_handling_client.process(stub)
error_handling_client.process(stub)
# No unhandled exception raised, test passed!
if __name__ == '__main__':
logging.basicConfig()
unittest.main(verbosity=2)

@ -169,9 +169,13 @@ class ServerCallbackReaderWriter {
// The following classes are the reactor interfaces that are to be implemented
// by the user, returned as the result of the method handler for a callback
// method, and activated by the call to OnStarted. Note that none of the classes
// are pure; all reactions have a default empty reaction so that the user class
// only needs to override those classes that it cares about.
// method, and activated by the call to OnStarted. The library guarantees that
// OnStarted will be called for any reactor that has been created using a
// method handler registered on a service. No operation initiation method may be
// called until after the call to OnStarted.
// Note that none of the classes are pure; all reactions have a default empty
// reaction so that the user class only needs to override those classes that it
// cares about.
/// \a ServerBidiReactor is the interface for a bidirectional streaming RPC.
template <class Request, class Response>
@ -179,6 +183,9 @@ class ServerBidiReactor : public internal::ServerReactor {
public:
~ServerBidiReactor() = default;
/// Do NOT call any operation initiation method (names that start with Start)
/// until after the library has called OnStarted on this object.
/// Send any initial metadata stored in the RPC context. If not invoked,
/// any initial metadata will be passed along with the first Write or the
/// Finish (if there are no writes).
@ -245,7 +252,8 @@ class ServerBidiReactor : public internal::ServerReactor {
/// \param[in] s The status outcome of this RPC
void Finish(Status s) { stream_->Finish(std::move(s)); }
/// Notify the application that a streaming RPC has started
/// Notify the application that a streaming RPC has started and that it is now
/// ok to call any operation initation method.
///
/// \param[in] context The context object now associated with this RPC
virtual void OnStarted(ServerContext* context) {}

@ -100,49 +100,52 @@ struct QueuedPick {
};
typedef struct client_channel_channel_data {
//
// Fields set at construction and never modified.
//
bool deadline_checking_enabled;
bool enable_retries;
size_t per_rpc_retry_buffer_size;
/** combiner protecting all variables below in this data structure */
grpc_combiner* combiner;
/** owning stack */
grpc_channel_stack* owning_stack;
/** interested parties (owned) */
grpc_pollset_set* interested_parties;
// Client channel factory.
grpc_core::ClientChannelFactory* client_channel_factory;
// Subchannel pool.
grpc_core::RefCountedPtr<grpc_core::SubchannelPoolInterface> subchannel_pool;
grpc_core::channelz::ClientChannelNode* channelz_node;
// Resolving LB policy.
grpc_core::OrphanablePtr<LoadBalancingPolicy> resolving_lb_policy;
// Subchannel picker from LB policy.
//
// Fields used in the data plane. Protected by data_plane_combiner.
//
grpc_combiner* data_plane_combiner;
grpc_core::UniquePtr<LoadBalancingPolicy::SubchannelPicker> picker;
// Linked list of queued picks.
QueuedPick* queued_picks;
bool have_service_config;
/** retry throttle data from service config */
QueuedPick* queued_picks; // Linked list of queued picks.
// Data from service config.
bool received_service_config_data;
grpc_core::RefCountedPtr<ServerRetryThrottleData> retry_throttle_data;
/** per-method service config data */
grpc_core::RefCountedPtr<ClientChannelMethodParamsTable> method_params_table;
/* the following properties are guarded by a mutex since APIs require them
to be instantaneously available */
gpr_mu info_mu;
grpc_core::UniquePtr<char> info_lb_policy_name;
grpc_core::UniquePtr<char> info_service_config_json;
//
// Fields used in the control plane. Protected by combiner.
//
grpc_combiner* combiner;
grpc_pollset_set* interested_parties;
grpc_core::RefCountedPtr<grpc_core::SubchannelPoolInterface> subchannel_pool;
grpc_core::OrphanablePtr<LoadBalancingPolicy> resolving_lb_policy;
grpc_connectivity_state_tracker state_tracker;
grpc_error* disconnect_error;
/* external_connectivity_watcher_list head is guarded by its own mutex, since
* counts need to be grabbed immediately without polling on a cq */
//
// Fields accessed from both data plane and control plane combiners.
//
grpc_core::Atomic<grpc_error*> disconnect_error;
// external_connectivity_watcher_list head is guarded by its own mutex, since
// counts need to be grabbed immediately without polling on a CQ.
gpr_mu external_connectivity_watcher_list_mu;
struct external_connectivity_watcher* external_connectivity_watcher_list_head;
// The following properties are guarded by a mutex since APIs require them
// to be instantaneously available.
gpr_mu info_mu;
grpc_core::UniquePtr<char> info_lb_policy_name;
grpc_core::UniquePtr<char> info_service_config_json;
} channel_data;
// Forward declarations.
@ -166,30 +169,98 @@ static const char* get_channel_connectivity_state_change_string(
GPR_UNREACHABLE_CODE(return "UNKNOWN");
}
static void set_connectivity_state_and_picker_locked(
channel_data* chand, grpc_connectivity_state state, grpc_error* state_error,
const char* reason,
grpc_core::UniquePtr<LoadBalancingPolicy::SubchannelPicker> picker) {
// Update connectivity state.
grpc_connectivity_state_set(&chand->state_tracker, state, state_error,
reason);
if (chand->channelz_node != nullptr) {
chand->channelz_node->AddTraceEvent(
grpc_core::channelz::ChannelTrace::Severity::Info,
grpc_slice_from_static_string(
get_channel_connectivity_state_change_string(state)));
namespace grpc_core {
namespace {
// A fire-and-forget class that sets the channel's connectivity state
// and then hops into the data plane combiner to update the picker.
// Must be instantiated while holding the control plane combiner.
// Deletes itself when done.
class ConnectivityStateAndPickerSetter {
public:
ConnectivityStateAndPickerSetter(
channel_data* chand, grpc_connectivity_state state,
grpc_error* state_error, const char* reason,
UniquePtr<LoadBalancingPolicy::SubchannelPicker> picker)
: chand_(chand), picker_(std::move(picker)) {
// Update connectivity state here, while holding control plane combiner.
grpc_connectivity_state_set(&chand->state_tracker, state, state_error,
reason);
if (chand->channelz_node != nullptr) {
chand->channelz_node->AddTraceEvent(
channelz::ChannelTrace::Severity::Info,
grpc_slice_from_static_string(
get_channel_connectivity_state_change_string(state)));
}
// Bounce into the data plane combiner to reset the picker.
GRPC_CHANNEL_STACK_REF(chand->owning_stack,
"ConnectivityStateAndPickerSetter");
GRPC_CLOSURE_INIT(&closure_, SetPicker, this,
grpc_combiner_scheduler(chand->data_plane_combiner));
GRPC_CLOSURE_SCHED(&closure_, GRPC_ERROR_NONE);
}
// Update picker.
chand->picker = std::move(picker);
// Re-process queued picks.
for (QueuedPick* pick = chand->queued_picks; pick != nullptr;
pick = pick->next) {
start_pick_locked(pick->elem, GRPC_ERROR_NONE);
private:
static void SetPicker(void* arg, grpc_error* ignored) {
auto* self = static_cast<ConnectivityStateAndPickerSetter*>(arg);
// Update picker.
self->chand_->picker = std::move(self->picker_);
// Re-process queued picks.
for (QueuedPick* pick = self->chand_->queued_picks; pick != nullptr;
pick = pick->next) {
start_pick_locked(pick->elem, GRPC_ERROR_NONE);
}
// Clean up.
GRPC_CHANNEL_STACK_UNREF(self->chand_->owning_stack,
"ConnectivityStateAndPickerSetter");
Delete(self);
}
}
namespace grpc_core {
namespace {
channel_data* chand_;
UniquePtr<LoadBalancingPolicy::SubchannelPicker> picker_;
grpc_closure closure_;
};
// A fire-and-forget class that sets the channel's service config data
// in the data plane combiner. Deletes itself when done.
class ServiceConfigSetter {
public:
ServiceConfigSetter(
channel_data* chand,
RefCountedPtr<ServerRetryThrottleData> retry_throttle_data,
RefCountedPtr<ClientChannelMethodParamsTable> method_params_table)
: chand_(chand),
retry_throttle_data_(std::move(retry_throttle_data)),
method_params_table_(std::move(method_params_table)) {
GRPC_CHANNEL_STACK_REF(chand->owning_stack, "ServiceConfigSetter");
GRPC_CLOSURE_INIT(&closure_, SetServiceConfigData, this,
grpc_combiner_scheduler(chand->data_plane_combiner));
GRPC_CLOSURE_SCHED(&closure_, GRPC_ERROR_NONE);
}
private:
static void SetServiceConfigData(void* arg, grpc_error* ignored) {
ServiceConfigSetter* self = static_cast<ServiceConfigSetter*>(arg);
channel_data* chand = self->chand_;
// Update channel state.
chand->received_service_config_data = true;
chand->retry_throttle_data = std::move(self->retry_throttle_data_);
chand->method_params_table = std::move(self->method_params_table_);
// Apply service config to queued picks.
for (QueuedPick* pick = chand->queued_picks; pick != nullptr;
pick = pick->next) {
maybe_apply_service_config_to_call_locked(pick->elem);
}
// Clean up.
GRPC_CHANNEL_STACK_UNREF(self->chand_->owning_stack, "ServiceConfigSetter");
Delete(self);
}
channel_data* chand_;
RefCountedPtr<ServerRetryThrottleData> retry_throttle_data_;
RefCountedPtr<ClientChannelMethodParamsTable> method_params_table_;
grpc_closure closure_;
};
class ClientChannelControlHelper
: public LoadBalancingPolicy::ChannelControlHelper {
@ -222,8 +293,10 @@ class ClientChannelControlHelper
void UpdateState(
grpc_connectivity_state state, grpc_error* state_error,
UniquePtr<LoadBalancingPolicy::SubchannelPicker> picker) override {
grpc_error* disconnect_error =
chand_->disconnect_error.Load(grpc_core::MemoryOrder::ACQUIRE);
if (grpc_client_channel_routing_trace.enabled()) {
const char* extra = chand_->disconnect_error == GRPC_ERROR_NONE
const char* extra = disconnect_error == GRPC_ERROR_NONE
? ""
: " (ignoring -- channel shutting down)";
gpr_log(GPR_INFO, "chand=%p: update: state=%s error=%s picker=%p%s",
@ -231,9 +304,10 @@ class ClientChannelControlHelper
grpc_error_string(state_error), picker.get(), extra);
}
// Do update only if not shutting down.
if (chand_->disconnect_error == GRPC_ERROR_NONE) {
set_connectivity_state_and_picker_locked(chand_, state, state_error,
"helper", std::move(picker));
if (disconnect_error == GRPC_ERROR_NONE) {
// Will delete itself.
New<ConnectivityStateAndPickerSetter>(chand_, state, state_error,
"helper", std::move(picker));
} else {
GRPC_ERROR_UNREF(state_error);
}
@ -255,7 +329,6 @@ static bool process_resolver_result_locked(
void* arg, grpc_core::Resolver::Result* result, const char** lb_policy_name,
grpc_core::RefCountedPtr<LoadBalancingPolicy::Config>* lb_policy_config) {
channel_data* chand = static_cast<channel_data*>(arg);
chand->have_service_config = true;
ProcessedResolverResult resolver_result(result, chand->enable_retries);
grpc_core::UniquePtr<char> service_config_json =
resolver_result.service_config_json();
@ -263,9 +336,11 @@ static bool process_resolver_result_locked(
gpr_log(GPR_INFO, "chand=%p: resolver returned service config: \"%s\"",
chand, service_config_json.get());
}
// Update channel state.
chand->retry_throttle_data = resolver_result.retry_throttle_data();
chand->method_params_table = resolver_result.method_params_table();
// Create service config setter to update channel state in the data
// plane combiner. Destroys itself when done.
grpc_core::New<grpc_core::ServiceConfigSetter>(
chand, resolver_result.retry_throttle_data(),
resolver_result.method_params_table());
// Swap out the data used by cc_get_channel_info().
gpr_mu_lock(&chand->info_mu);
chand->info_lb_policy_name = resolver_result.lb_policy_name();
@ -280,11 +355,6 @@ static bool process_resolver_result_locked(
// Return results.
*lb_policy_name = chand->info_lb_policy_name.get();
*lb_policy_config = resolver_result.lb_policy_config();
// Apply service config to queued picks.
for (QueuedPick* pick = chand->queued_picks; pick != nullptr;
pick = pick->next) {
maybe_apply_service_config_to_call_locked(pick->elem);
}
return service_config_changed;
}
@ -342,12 +412,16 @@ static void start_transport_op_locked(void* arg, grpc_error* error_ignored) {
}
if (op->disconnect_with_error != GRPC_ERROR_NONE) {
chand->disconnect_error = op->disconnect_with_error;
grpc_error* error = GRPC_ERROR_NONE;
GPR_ASSERT(chand->disconnect_error.CompareExchangeStrong(
&error, op->disconnect_with_error, grpc_core::MemoryOrder::ACQ_REL,
grpc_core::MemoryOrder::ACQUIRE));
grpc_pollset_set_del_pollset_set(
chand->resolving_lb_policy->interested_parties(),
chand->interested_parties);
chand->resolving_lb_policy.reset();
set_connectivity_state_and_picker_locked(
// Will delete itself.
grpc_core::New<grpc_core::ConnectivityStateAndPickerSetter>(
chand, GRPC_CHANNEL_SHUTDOWN, GRPC_ERROR_REF(op->disconnect_with_error),
"shutdown from API",
grpc_core::UniquePtr<LoadBalancingPolicy::SubchannelPicker>(
@ -397,10 +471,12 @@ static grpc_error* cc_init_channel_elem(grpc_channel_element* elem,
GPR_ASSERT(args->is_last);
GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
// Initialize data members.
chand->data_plane_combiner = grpc_combiner_create();
chand->combiner = grpc_combiner_create();
grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE,
"client_channel");
chand->disconnect_error = GRPC_ERROR_NONE;
chand->disconnect_error.Store(GRPC_ERROR_NONE,
grpc_core::MemoryOrder::RELAXED);
gpr_mu_init(&chand->info_mu);
gpr_mu_init(&chand->external_connectivity_watcher_list_mu);
@ -511,8 +587,10 @@ static void cc_destroy_channel_elem(grpc_channel_element* elem) {
chand->method_params_table.reset();
grpc_client_channel_stop_backup_polling(chand->interested_parties);
grpc_pollset_set_destroy(chand->interested_parties);
GRPC_COMBINER_UNREF(chand->data_plane_combiner, "client_channel");
GRPC_COMBINER_UNREF(chand->combiner, "client_channel");
GRPC_ERROR_UNREF(chand->disconnect_error);
GRPC_ERROR_UNREF(
chand->disconnect_error.Load(grpc_core::MemoryOrder::RELAXED));
grpc_connectivity_state_destroy(&chand->state_tracker);
gpr_mu_destroy(&chand->info_mu);
gpr_mu_destroy(&chand->external_connectivity_watcher_list_mu);
@ -1261,7 +1339,7 @@ static void do_retry(grpc_call_element* elem,
}
// Schedule retry after computed delay.
GRPC_CLOSURE_INIT(&calld->pick_closure, start_pick_locked, elem,
grpc_combiner_scheduler(chand->combiner));
grpc_combiner_scheduler(chand->data_plane_combiner));
grpc_timer_init(&calld->retry_timer, next_attempt_time, &calld->pick_closure);
// Update bookkeeping.
if (retry_state != nullptr) retry_state->retry_dispatched = true;
@ -2488,7 +2566,7 @@ class QueuedPickCanceller {
auto* chand = static_cast<channel_data*>(elem->channel_data);
GRPC_CALL_STACK_REF(calld->owning_call, "QueuedPickCanceller");
GRPC_CLOSURE_INIT(&closure_, &CancelLocked, this,
grpc_combiner_scheduler(chand->combiner));
grpc_combiner_scheduler(chand->data_plane_combiner));
grpc_call_combiner_set_notify_on_cancel(calld->call_combiner, &closure_);
}
@ -2628,7 +2706,7 @@ static void maybe_apply_service_config_to_call_locked(grpc_call_element* elem) {
call_data* calld = static_cast<call_data*>(elem->call_data);
// Apply service config data to the call only once, and only if the
// channel has the data available.
if (GPR_LIKELY(chand->have_service_config &&
if (GPR_LIKELY(chand->received_service_config_data &&
!calld->service_config_applied)) {
calld->service_config_applied = true;
apply_service_config_to_call_locked(elem);
@ -2676,7 +2754,7 @@ static void start_pick_locked(void* arg, grpc_error* error) {
.send_initial_metadata_flags;
// Apply service config to call if needed.
maybe_apply_service_config_to_call_locked(elem);
// When done, we schedule this closure to leave the channel combiner.
// When done, we schedule this closure to leave the data plane combiner.
GRPC_CLOSURE_INIT(&calld->pick_closure, pick_done, elem,
grpc_schedule_on_exec_ctx);
// Attempt pick.
@ -2691,12 +2769,14 @@ static void start_pick_locked(void* arg, grpc_error* error) {
grpc_error_string(error));
}
switch (pick_result) {
case LoadBalancingPolicy::PICK_TRANSIENT_FAILURE:
case LoadBalancingPolicy::PICK_TRANSIENT_FAILURE: {
// If we're shutting down, fail all RPCs.
if (chand->disconnect_error != GRPC_ERROR_NONE) {
grpc_error* disconnect_error =
chand->disconnect_error.Load(grpc_core::MemoryOrder::ACQUIRE);
if (disconnect_error != GRPC_ERROR_NONE) {
GRPC_ERROR_UNREF(error);
GRPC_CLOSURE_SCHED(&calld->pick_closure,
GRPC_ERROR_REF(chand->disconnect_error));
GRPC_ERROR_REF(disconnect_error));
break;
}
// If wait_for_ready is false, then the error indicates the RPC
@ -2722,7 +2802,8 @@ static void start_pick_locked(void* arg, grpc_error* error) {
// If wait_for_ready is true, then queue to retry when we get a new
// picker.
GRPC_ERROR_UNREF(error);
// Fallthrough
}
// Fallthrough
case LoadBalancingPolicy::PICK_QUEUE:
if (!calld->pick_queued) add_call_to_queued_picks_locked(elem);
break;
@ -2816,7 +2897,8 @@ static void cc_start_transport_stream_op_batch(
}
GRPC_CLOSURE_SCHED(
GRPC_CLOSURE_INIT(&batch->handler_private.closure, start_pick_locked,
elem, grpc_combiner_scheduler(chand->combiner)),
elem,
grpc_combiner_scheduler(chand->data_plane_combiner)),
GRPC_ERROR_NONE);
} else {
// For all other batches, release the call combiner.

@ -140,10 +140,9 @@ LoadBalancingPolicy::PickResult LoadBalancingPolicy::QueuePicker::Pick(
// the time this function returns, the pick will already have
// been processed, and we'll be trying to re-process the same
// pick again, leading to a crash.
// 2. In a subsequent PR, we will split the data plane and control
// plane synchronization into separate combiners, at which
// point this will need to hop from the data plane combiner into
// the control plane combiner.
// 2. We are currently running in the data plane combiner, but we
// need to bounce into the control plane combiner to call
// ExitIdleLocked().
if (!exit_idle_called_) {
exit_idle_called_ = true;
parent_->Ref().release(); // ref held by closure.

@ -234,12 +234,19 @@ class GrpcLb : public LoadBalancingPolicy {
// Returns the LB token to use for a drop, or null if the call
// should not be dropped.
// Intended to be called from picker, so calls will be externally
// synchronized.
//
// Note: This is called from the picker, so it will be invoked in
// the channel's data plane combiner, NOT the control plane
// combiner. It should not be accessed by any other part of the LB
// policy.
const char* ShouldDrop();
private:
grpc_grpclb_serverlist* serverlist_;
// Guarded by the channel's data plane combiner, NOT the control
// plane combiner. It should not be accessed by anything but the
// picker via the ShouldDrop() method.
size_t drop_index_ = 0;
};

@ -160,8 +160,6 @@ void Fork::GlobalInit() {
if (!override_enabled_) {
#ifdef GRPC_ENABLE_FORK_SUPPORT
support_enabled_ = true;
#else
support_enabled_ = false;
#endif
bool env_var_set = false;
char* env = gpr_getenv("GRPC_ENABLE_FORK_SUPPORT");

@ -29,6 +29,7 @@
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/iomgr/closure.h"
#include "src/core/lib/iomgr/error_cfstream.h"
#include "src/core/lib/iomgr/exec_ctx.h"
extern grpc_core::TraceFlag grpc_tcp_trace;
@ -54,6 +55,8 @@ void CFStreamHandle::ReadCallback(CFReadStreamRef stream,
void* client_callback_info) {
grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
grpc_core::ExecCtx exec_ctx;
grpc_error* error;
CFErrorRef stream_error;
CFStreamHandle* handle = static_cast<CFStreamHandle*>(client_callback_info);
if (grpc_tcp_trace.enabled()) {
gpr_log(GPR_DEBUG, "CFStream ReadCallback (%p, %p, %lu, %p)", handle,
@ -68,8 +71,15 @@ void CFStreamHandle::ReadCallback(CFReadStreamRef stream,
handle->read_event_.SetReady();
break;
case kCFStreamEventErrorOccurred:
handle->open_event_.SetReady();
handle->read_event_.SetReady();
stream_error = CFReadStreamCopyError(stream);
error = grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_CFERROR(stream_error, "read error"),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
CFRelease(stream_error);
handle->open_event_.SetShutdown(GRPC_ERROR_REF(error));
handle->write_event_.SetShutdown(GRPC_ERROR_REF(error));
handle->read_event_.SetShutdown(GRPC_ERROR_REF(error));
GRPC_ERROR_UNREF(error);
break;
default:
GPR_UNREACHABLE_CODE(return );
@ -80,6 +90,8 @@ void CFStreamHandle::WriteCallback(CFWriteStreamRef stream,
void* clientCallBackInfo) {
grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
grpc_core::ExecCtx exec_ctx;
grpc_error* error;
CFErrorRef stream_error;
CFStreamHandle* handle = static_cast<CFStreamHandle*>(clientCallBackInfo);
if (grpc_tcp_trace.enabled()) {
gpr_log(GPR_DEBUG, "CFStream WriteCallback (%p, %p, %lu, %p)", handle,
@ -94,8 +106,15 @@ void CFStreamHandle::WriteCallback(CFWriteStreamRef stream,
handle->write_event_.SetReady();
break;
case kCFStreamEventErrorOccurred:
handle->open_event_.SetReady();
handle->write_event_.SetReady();
stream_error = CFWriteStreamCopyError(stream);
error = grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_CFERROR(stream_error, "write error"),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
CFRelease(stream_error);
handle->open_event_.SetShutdown(GRPC_ERROR_REF(error));
handle->write_event_.SetShutdown(GRPC_ERROR_REF(error));
handle->read_event_.SetShutdown(GRPC_ERROR_REF(error));
GRPC_ERROR_UNREF(error);
break;
default:
GPR_UNREACHABLE_CODE(return );

@ -213,10 +213,12 @@ static void tcp_connect(grpc_closure* on_done, grpc_endpoint** endpoint,
failure:
GPR_ASSERT(error != GRPC_ERROR_NONE);
char* target_uri = grpc_sockaddr_to_uri(addr);
grpc_error* final_error = grpc_error_set_str(
GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING("Failed to connect",
&error, 1),
GRPC_ERROR_STR_TARGET_ADDRESS, grpc_slice_from_copied_string(target_uri));
grpc_error* final_error =
grpc_error_set_str(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Failed to connect", &error, 1),
GRPC_ERROR_STR_TARGET_ADDRESS,
grpc_slice_from_copied_string(
target_uri == nullptr ? "NULL" : target_uri));
GRPC_ERROR_UNREF(error);
if (socket != NULL) {
grpc_winsocket_destroy(socket);

@ -18,8 +18,6 @@
#include <grpcpp/channel.h>
#include <chrono>
#include <condition_variable>
#include <cstring>
#include <memory>
#include <mutex>
@ -41,12 +39,7 @@
#include <grpcpp/support/channel_arguments.h>
#include <grpcpp/support/config.h>
#include <grpcpp/support/status.h>
#include <grpcpp/support/time.h>
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/gprpp/thd.h"
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/surface/completion_queue.h"
namespace grpc {

@ -59,7 +59,7 @@ namespace Grpc.Core
/// <summary>
/// Creates a channel that connects to a specific host.
/// Port will default to 80 for an unsecure channel and to 443 for a secure channel.
/// Port will default to 80 for an unsecure channel or to 443 for a secure channel.
/// </summary>
/// <param name="target">Target of the channel.</param>
/// <param name="credentials">Credentials to secure the channel.</param>
@ -112,7 +112,7 @@ namespace Grpc.Core
/// <summary>
/// Gets current connectivity state of this channel.
/// After channel is has been shutdown, <c>ChannelState.Shutdown</c> will be returned.
/// After channel has been shutdown, <c>ChannelState.Shutdown</c> will be returned.
/// </summary>
public ChannelState State
{
@ -132,7 +132,7 @@ namespace Grpc.Core
/// <summary>
/// Returned tasks completes once channel state has become different from
/// given lastObservedState.
/// If deadline is reached or and error occurs, returned task is cancelled.
/// If deadline is reached or an error occurs, returned task is cancelled.
/// </summary>
public async Task WaitForStateChangedAsync(ChannelState lastObservedState, DateTime? deadline = null)
{

@ -67,27 +67,22 @@ ZEND_GET_MODULE(grpc)
/* {{{ PHP_INI
*/
/* Remove comments and fill if you need to have entries in php.ini
PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("grpc.global_value", "42", PHP_INI_ALL, OnUpdateLong,
global_value, zend_grpc_globals, grpc_globals)
STD_PHP_INI_ENTRY("grpc.global_string", "foobar", PHP_INI_ALL,
OnUpdateString, global_string, zend_grpc_globals,
grpc_globals)
STD_PHP_INI_ENTRY("grpc.enable_fork_support", "0", PHP_INI_SYSTEM, OnUpdateBool,
enable_fork_support, zend_grpc_globals, grpc_globals)
STD_PHP_INI_ENTRY("grpc.poll_strategy", NULL, PHP_INI_SYSTEM, OnUpdateString,
poll_strategy, zend_grpc_globals, grpc_globals)
PHP_INI_END()
*/
/* }}} */
/* {{{ php_grpc_init_globals
*/
/* Uncomment this function if you have INI entries
static void php_grpc_init_globals(zend_grpc_globals *grpc_globals)
{
grpc_globals->global_value = 0;
grpc_globals->global_string = NULL;
}
*/
static void php_grpc_init_globals(zend_grpc_globals *grpc_globals) {
grpc_globals->enable_fork_support = 0;
grpc_globals->poll_strategy = NULL;
}
/* }}} */
void create_new_channel(
wrapped_grpc_channel *channel,
char *target,
@ -180,7 +175,7 @@ void postfork_child() {
grpc_php_shutdown_completion_queue(TSRMLS_C);
// clean-up grpc_core
grpc_shutdown();
grpc_shutdown_blocking();
if (grpc_is_initialized() > 0) {
zend_throw_exception(spl_ce_UnexpectedValueException,
"Oops, failed to shutdown gRPC Core after fork()",
@ -208,12 +203,22 @@ void register_fork_handlers() {
}
}
void apply_ini_settings() {
if (GRPC_G(enable_fork_support)) {
setenv("GRPC_ENABLE_FORK_SUPPORT", "1", 1 /* overwrite? */);
}
if (GRPC_G(poll_strategy)) {
setenv("GRPC_POLL_STRATEGY", GRPC_G(poll_strategy), 1 /* overwrite? */);
}
}
/* {{{ PHP_MINIT_FUNCTION
*/
PHP_MINIT_FUNCTION(grpc) {
/* If you have INI entries, uncomment these lines
REGISTER_INI_ENTRIES();
*/
ZEND_INIT_MODULE_GLOBALS(grpc, php_grpc_init_globals, NULL);
REGISTER_INI_ENTRIES();
/* Register call error constants */
REGISTER_LONG_CONSTANT("Grpc\\CALL_OK", GRPC_CALL_OK,
CONST_CS | CONST_PERSISTENT);
@ -349,9 +354,7 @@ PHP_MINIT_FUNCTION(grpc) {
/* {{{ PHP_MSHUTDOWN_FUNCTION
*/
PHP_MSHUTDOWN_FUNCTION(grpc) {
/* uncomment this line if you have INI entries
UNREGISTER_INI_ENTRIES();
*/
UNREGISTER_INI_ENTRIES();
// WARNING: This function IS being called by PHP when the extension
// is unloaded but the logs were somehow suppressed.
if (GRPC_G(initialized)) {
@ -375,9 +378,7 @@ PHP_MINFO_FUNCTION(grpc) {
php_info_print_table_row(2, "grpc support", "enabled");
php_info_print_table_row(2, "grpc module version", PHP_GRPC_VERSION);
php_info_print_table_end();
/* Remove comments if you have entries in php.ini
DISPLAY_INI_ENTRIES();
*/
DISPLAY_INI_ENTRIES();
}
/* }}} */
@ -385,6 +386,7 @@ PHP_MINFO_FUNCTION(grpc) {
*/
PHP_RINIT_FUNCTION(grpc) {
if (!GRPC_G(initialized)) {
apply_ini_settings();
grpc_init();
register_fork_handlers();
grpc_php_init_completion_queue(TSRMLS_C);

@ -66,6 +66,8 @@ PHP_RINIT_FUNCTION(grpc);
*/
ZEND_BEGIN_MODULE_GLOBALS(grpc)
zend_bool initialized;
zend_bool enable_fork_support;
char *poll_strategy;
ZEND_END_MODULE_GLOBALS(grpc)
/* In every utility function you add that needs to use variables

@ -0,0 +1,15 @@
--TEST--
Ensure default ini settings
--SKIPIF--
<?php if (!extension_loaded("grpc")) print "skip"; ?>
--FILE--
<?php
if (ini_get('grpc.enable_fork_support')) {
die('grpc.enable_fork_support not off by default');
}
if (ini_get('grpc.poll_strategy') !== "") {
die('grpc.poll_strategy not empty by default');
}
echo 'ok';
--EXPECT--
ok

@ -0,0 +1,24 @@
--TEST--
Ensure ini settings are handled
--SKIPIF--
<?php if (!extension_loaded("grpc")) print "skip"; ?>
--INI--
grpc.enable_fork_support = 1
grpc.poll_strategy = epoll1
--FILE--
<?php
if (!ini_get('grpc.enable_fork_support')) {
die('grpc.enable_fork_support not set');
}
if (!getenv('GRPC_ENABLE_FORK_SUPPORT')) {
die('env GRPC_ENABLE_FORK_SUPPORT not set');
}
if (ini_get('grpc.poll_strategy') !== 'epoll1') {
die('grpc.poll_strategy !== epoll1');
}
if (getenv('GRPC_POLL_STRATEGY') !== 'epoll1') {
die('env GRPC_POLL_STRATEGY not epoll1');
}
echo 'ok';
--EXPECT--
ok

@ -4,5 +4,6 @@ py_library(
visibility = [
"//src/python/grpcio_tests/tests/status:__subpackages__",
"//src/python/grpcio_tests/tests/interop:__subpackages__",
"//examples/python/errors:__subpackages__",
],
)

@ -29,4 +29,5 @@ grpc_cc_binary(
"//:grpc",
"//test/core/util:grpc_test_util",
],
tags = ["no_windows"],
)

@ -52,6 +52,7 @@ grpc_cc_test(
"//:grpc",
"//test/core/util:grpc_test_util",
],
tags = ["no_windows"],
)
grpc_cc_test(

@ -31,7 +31,8 @@ def _fixture_options(
is_http2 = True,
supports_proxy_auth = False,
supports_write_buffering = True,
client_channel = True):
client_channel = True,
supports_msvc = True):
return struct(
fullstack = fullstack,
includes_proxy = includes_proxy,
@ -44,6 +45,7 @@ def _fixture_options(
supports_proxy_auth = supports_proxy_auth,
supports_write_buffering = supports_write_buffering,
client_channel = client_channel,
supports_msvc = supports_msvc,
#_platforms=_platforms,
)
@ -120,10 +122,11 @@ END2END_NOSEC_FIXTURES = {
client_channel = False,
secure = False,
_platforms = ["linux", "mac", "posix"],
supports_msvc = False,
),
"h2_full": _fixture_options(secure = False),
"h2_full+pipe": _fixture_options(secure = False, _platforms = ["linux"]),
"h2_full+trace": _fixture_options(secure = False, tracing = True),
"h2_full+pipe": _fixture_options(secure = False, _platforms = ["linux"], supports_msvc = False),
"h2_full+trace": _fixture_options(secure = False, tracing = True, supports_msvc = False),
"h2_full+workarounds": _fixture_options(secure = False),
"h2_http_proxy": _fixture_options(secure = False, supports_proxy_auth = True),
"h2_proxy": _fixture_options(secure = False, includes_proxy = True),
@ -152,6 +155,7 @@ END2END_NOSEC_FIXTURES = {
dns_resolver = False,
_platforms = ["linux", "mac", "posix"],
secure = False,
supports_msvc = False,
),
}
@ -463,4 +467,5 @@ def grpc_end2end_nosec_tests():
t,
poller,
],
tags = ["no_windows"],
)

@ -81,6 +81,7 @@ grpc_cc_test(
"//:grpc",
"//test/core/util:grpc_test_util",
],
tags = ["no_windows"],
)
grpc_cc_test(
@ -92,6 +93,7 @@ grpc_cc_test(
"//:grpc",
"//test/core/util:grpc_test_util",
],
tags = ["no_windows"],
)
grpc_cc_test(
@ -103,6 +105,7 @@ grpc_cc_test(
"//:grpc",
"//test/core/util:grpc_test_util",
],
tags = ["no_windows"],
)
grpc_cc_test(
@ -139,6 +142,7 @@ grpc_cc_test(
"//:grpc",
"//test/core/util:grpc_test_util",
],
tags = ["no_windows"],
)
grpc_cc_test(
@ -153,6 +157,7 @@ grpc_cc_test(
"//:grpc",
"//test/core/util:grpc_test_util",
],
tags = ["no_windows"],
)
grpc_cc_test(
@ -214,6 +219,7 @@ grpc_cc_test(
"//:grpc",
"//test/core/util:grpc_test_util",
],
tags = ["no_windows"],
)
grpc_cc_test(
@ -225,6 +231,7 @@ grpc_cc_test(
"//:grpc",
"//test/core/util:grpc_test_util",
],
tags = ["no_windows"],
)
grpc_cc_test(
@ -237,6 +244,7 @@ grpc_cc_test(
"//:grpc",
"//test/core/util:grpc_test_util",
],
tags = ["no_windows"],
)
grpc_cc_test(
@ -259,6 +267,7 @@ grpc_cc_test(
"//:grpc",
"//test/core/util:grpc_test_util",
],
tags = ["no_windows"],
)
grpc_cc_test(
@ -303,4 +312,5 @@ grpc_cc_test(
"//:grpc",
"//test/core/util:grpc_test_util",
],
tags = ["no_windows"],
)

@ -28,6 +28,7 @@ grpc_cc_test(
"//:grpc++_unsecure",
"//test/core/util:grpc_test_util_unsecure",
],
tags = ["no_windows"],
)
grpc_cc_test(

@ -99,6 +99,7 @@ grpc_cc_test(
"//test/core/util:grpc_test_util",
"//test/cpp/util:test_util",
],
tags = ["no_windows"],
)
grpc_cc_test(
@ -633,6 +634,7 @@ grpc_cc_test(
"//test/core/util:grpc_test_util",
"//test/cpp/util:test_util",
],
tags = ["no_windows"],
)
grpc_cc_test(

@ -47,8 +47,10 @@
#include "test/cpp/end2end/test_service_impl.h"
#ifdef GRPC_CFSTREAM
using grpc::ClientAsyncResponseReader;
using grpc::testing::EchoRequest;
using grpc::testing::EchoResponse;
using grpc::testing::RequestParams;
using std::chrono::system_clock;
namespace grpc {
@ -60,8 +62,7 @@ class CFStreamTest : public ::testing::Test {
CFStreamTest()
: server_host_("grpctest"),
interface_("lo0"),
ipv4_address_("10.0.0.1"),
netmask_("/32"),
ipv4_address_("127.0.0.2"),
kRequestMessage_("🖖") {}
void DNSUp() {
@ -92,11 +93,13 @@ class CFStreamTest : public ::testing::Test {
}
void NetworkUp() {
gpr_log(GPR_DEBUG, "Bringing network up");
InterfaceUp();
DNSUp();
}
void NetworkDown() {
gpr_log(GPR_DEBUG, "Bringing network down");
InterfaceDown();
DNSDown();
}
@ -149,6 +152,27 @@ class CFStreamTest : public ::testing::Test {
EXPECT_TRUE(status.ok());
}
}
void SendAsyncRpc(
const std::unique_ptr<grpc::testing::EchoTestService::Stub>& stub,
RequestParams param = RequestParams()) {
EchoRequest request;
auto msg = std::to_string(ctr.load());
request.set_message(msg);
ctr++;
*request.mutable_param() = std::move(param);
AsyncClientCall* call = new AsyncClientCall;
call->response_reader =
stub->PrepareAsyncEcho(&call->context, request, &cq_);
call->response_reader->StartCall();
gpr_log(GPR_DEBUG, "Sending request: %s", msg.c_str());
call->response_reader->Finish(&call->reply, &call->status, (void*)call);
}
void ShutdownCQ() { cq_.Shutdown(); }
bool CQNext(void** tag, bool* ok) { return cq_.Next(tag, ok); }
bool WaitForChannelNotReady(Channel* channel, int timeout_seconds = 5) {
const gpr_timespec deadline =
@ -172,6 +196,13 @@ class CFStreamTest : public ::testing::Test {
return true;
}
struct AsyncClientCall {
EchoResponse reply;
ClientContext context;
Status status;
std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader;
};
private:
struct ServerData {
int port_;
@ -214,14 +245,14 @@ class CFStreamTest : public ::testing::Test {
}
};
CompletionQueue cq_;
const grpc::string server_host_;
const grpc::string interface_;
const grpc::string ipv4_address_;
const grpc::string netmask_;
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
std::unique_ptr<ServerData> server_;
int port_;
const grpc::string kRequestMessage_;
std::atomic_int ctr{0};
};
// gRPC should automatically detech network flaps (without enabling keepalives)
@ -261,6 +292,117 @@ TEST_F(CFStreamTest, NetworkTransition) {
sender.join();
}
// Network flaps while RPCs are in flight
TEST_F(CFStreamTest, NetworkFlapRpcsInFlight) {
auto channel = BuildChannel();
auto stub = BuildStub(channel);
std::atomic_int rpcs_sent{0};
// Channel should be in READY state after we send some RPCs
for (int i = 0; i < 10; ++i) {
SendAsyncRpc(stub);
++rpcs_sent;
}
EXPECT_TRUE(WaitForChannelReady(channel.get()));
// Bring down the network
NetworkDown();
std::thread thd = std::thread([this, &rpcs_sent]() {
void* got_tag;
bool ok = false;
bool network_down = true;
int total_completions = 0;
while (CQNext(&got_tag, &ok)) {
++total_completions;
GPR_ASSERT(ok);
AsyncClientCall* call = static_cast<AsyncClientCall*>(got_tag);
if (call->status.ok()) {
gpr_log(GPR_DEBUG, "RPC response: %s", call->reply.message().c_str());
} else {
gpr_log(GPR_DEBUG, "RPC failed with error: %s",
call->status.error_message().c_str());
// Bring network up when RPCs start failing
if (network_down) {
NetworkUp();
network_down = false;
}
}
delete call;
}
EXPECT_EQ(total_completions, rpcs_sent);
});
for (int i = 0; i < 100; ++i) {
SendAsyncRpc(stub);
std::this_thread::sleep_for(std::chrono::milliseconds(10));
++rpcs_sent;
}
ShutdownCQ();
thd.join();
}
// Send a bunch of RPCs, some of which are expected to fail.
// We should get back a response for all RPCs
TEST_F(CFStreamTest, ConcurrentRpc) {
auto channel = BuildChannel();
auto stub = BuildStub(channel);
std::atomic_int rpcs_sent{0};
std::thread thd = std::thread([this, &rpcs_sent]() {
void* got_tag;
bool ok = false;
bool network_down = true;
int total_completions = 0;
while (CQNext(&got_tag, &ok)) {
++total_completions;
GPR_ASSERT(ok);
AsyncClientCall* call = static_cast<AsyncClientCall*>(got_tag);
if (call->status.ok()) {
gpr_log(GPR_DEBUG, "RPC response: %s", call->reply.message().c_str());
} else {
gpr_log(GPR_DEBUG, "RPC failed: %s",
call->status.error_message().c_str());
// Bring network up when RPCs start failing
if (network_down) {
NetworkUp();
network_down = false;
}
}
delete call;
}
EXPECT_EQ(total_completions, rpcs_sent);
});
for (int i = 0; i < 10; ++i) {
if (i % 3 == 0) {
RequestParams param;
ErrorStatus* error = param.mutable_expected_error();
error->set_code(StatusCode::INTERNAL);
error->set_error_message("internal error");
SendAsyncRpc(stub, param);
} else if (i % 5 == 0) {
RequestParams param;
param.set_echo_metadata(true);
DebugInfo* info = param.mutable_debug_info();
info->add_stack_entries("stack_entry1");
info->add_stack_entries("stack_entry2");
info->set_detail("detailed debug info");
SendAsyncRpc(stub, param);
} else {
SendAsyncRpc(stub);
}
++rpcs_sent;
}
ShutdownCQ();
thd.join();
}
} // namespace
} // namespace testing
} // namespace grpc

@ -143,6 +143,7 @@ void LoopUntilCancelled(Alarm* alarm, ServerContext* context,
Status TestServiceImpl::Echo(ServerContext* context, const EchoRequest* request,
EchoResponse* response) {
gpr_log(GPR_DEBUG, "Request message was %s", request->message().c_str());
// A bit of sleep to make sure that short deadline tests fail
if (request->has_param() && request->param().server_sleep_us() > 0) {
gpr_sleep_until(

@ -161,4 +161,5 @@ grpc_cc_test(
"//test/cpp/util:test_config",
"//test/cpp/util:test_util",
],
tags = ["no_windows"],
)

@ -45,6 +45,7 @@ grpc_cc_library(
"//test/core/util:grpc_test_util_unsecure",
"//test/cpp/util:test_config",
],
tags = ["no_windows"],
)
grpc_cc_binary(
@ -52,6 +53,7 @@ grpc_cc_binary(
testonly = 1,
srcs = ["bm_closure.cc"],
deps = [":helpers"],
tags = ["no_windows"],
)
grpc_cc_binary(
@ -59,6 +61,7 @@ grpc_cc_binary(
testonly = 1,
srcs = ["bm_alarm.cc"],
deps = [":helpers"],
tags = ["no_windows"],
)
grpc_cc_binary(
@ -66,6 +69,7 @@ grpc_cc_binary(
testonly = 1,
srcs = ["bm_arena.cc"],
deps = [":helpers"],
tags = ["no_windows"],
)
grpc_cc_binary(
@ -73,6 +77,7 @@ grpc_cc_binary(
testonly = 1,
srcs = ["bm_byte_buffer.cc"],
deps = [":helpers"],
tags = ["no_windows"],
)
grpc_cc_binary(
@ -80,6 +85,7 @@ grpc_cc_binary(
testonly = 1,
srcs = ["bm_channel.cc"],
deps = [":helpers"],
tags = ["no_windows"],
)
grpc_cc_binary(
@ -87,6 +93,7 @@ grpc_cc_binary(
testonly = 1,
srcs = ["bm_call_create.cc"],
deps = [":helpers"],
tags = ["no_windows"],
)
grpc_cc_binary(
@ -94,6 +101,7 @@ grpc_cc_binary(
testonly = 1,
srcs = ["bm_cq.cc"],
deps = [":helpers"],
tags = ["no_windows"],
)
grpc_cc_binary(
@ -101,6 +109,7 @@ grpc_cc_binary(
testonly = 1,
srcs = ["bm_cq_multiple_threads.cc"],
deps = [":helpers"],
tags = ["no_windows"],
)
grpc_cc_binary(
@ -108,6 +117,7 @@ grpc_cc_binary(
testonly = 1,
srcs = ["bm_error.cc"],
deps = [":helpers"],
tags = ["no_windows"],
)
grpc_cc_library(
@ -117,6 +127,7 @@ grpc_cc_library(
"fullstack_streaming_ping_pong.h",
],
deps = [":helpers"],
tags = ["no_windows"],
)
grpc_cc_binary(
@ -126,6 +137,7 @@ grpc_cc_binary(
"bm_fullstack_streaming_ping_pong.cc",
],
deps = [":fullstack_streaming_ping_pong_h"],
tags = ["no_windows"],
)
grpc_cc_library(
@ -144,6 +156,7 @@ grpc_cc_binary(
"bm_fullstack_streaming_pump.cc",
],
deps = [":fullstack_streaming_pump_h"],
tags = ["no_windows"],
)
grpc_cc_binary(
@ -151,6 +164,7 @@ grpc_cc_binary(
testonly = 1,
srcs = ["bm_fullstack_trickle.cc"],
deps = [":helpers"],
tags = ["no_windows"],
)
grpc_cc_library(
@ -169,6 +183,7 @@ grpc_cc_binary(
"bm_fullstack_unary_ping_pong.cc",
],
deps = [":fullstack_unary_ping_pong_h"],
tags = ["no_windows"],
)
grpc_cc_binary(
@ -176,6 +191,7 @@ grpc_cc_binary(
testonly = 1,
srcs = ["bm_metadata.cc"],
deps = [":helpers"],
tags = ["no_windows"],
)
grpc_cc_binary(
@ -183,6 +199,7 @@ grpc_cc_binary(
testonly = 1,
srcs = ["bm_chttp2_hpack.cc"],
deps = [":helpers"],
tags = ["no_windows"],
)
grpc_cc_binary(
@ -202,4 +219,5 @@ grpc_cc_binary(
testonly = 1,
srcs = ["bm_timer.cc"],
deps = [":helpers"],
tags = ["no_windows"],
)

@ -33,6 +33,7 @@ def generate_resolver_component_tests():
"//:gpr",
"//test/cpp/util:test_config",
],
tags = ["no_windows"],
)
# meant to be invoked only through the top-level shell script driver
grpc_cc_binary(
@ -52,6 +53,7 @@ def generate_resolver_component_tests():
"//:gpr",
"//test/cpp/util:test_config",
],
tags = ["no_windows"],
)
grpc_cc_test(
name = "resolver_component_tests_runner_invoker%s" % unsecure_build_config_suffix,
@ -77,5 +79,6 @@ def generate_resolver_component_tests():
args = [
"--test_bin_name=resolver_component_test%s" % unsecure_build_config_suffix,
"--running_under_bazel=true",
]
],
tags = ["no_windows"],
)

@ -31,4 +31,5 @@ grpc_cc_test(
"//src/proto/grpc/testing:echo_proto",
"//test/core/util:grpc_test_util_base",
],
tags = ["no_windows"],
)

@ -75,5 +75,6 @@ def json_run_localhost_batch():
],
tags = [
"json_run_localhost",
"no_windows",
],
)

@ -29,6 +29,7 @@ grpc_cc_test(
"//src/proto/grpc/testing:echo_proto",
"//test/core/util:grpc_test_util_unsecure",
],
tags = ["no_windows"],
)
grpc_cc_test(
@ -42,6 +43,7 @@ grpc_cc_test(
"//src/proto/grpc/testing:echo_proto",
"//test/core/util:grpc_test_util_unsecure",
],
tags = ["no_windows"],
)
grpc_cc_test(
@ -55,4 +57,5 @@ grpc_cc_test(
"//src/proto/grpc/testing:echo_proto",
"//test/core/util:grpc_test_util_unsecure",
],
tags = ["no_windows"],
)

@ -45,6 +45,7 @@ grpc_cc_test(
"//:lb_server_load_reporting_filter",
"//test/core/util:grpc_test_util",
],
tags = ["no_windows"],
)
grpc_cc_test(

@ -44,14 +44,17 @@ ProtoReflectionDescriptorDatabase::~ProtoReflectionDescriptorDatabase() {
Status status = stream_->Finish();
if (!status.ok()) {
if (status.error_code() == StatusCode::UNIMPLEMENTED) {
gpr_log(GPR_INFO,
fprintf(stderr,
"Reflection request not implemented; "
"is the ServerReflection service enabled?");
"is the ServerReflection service enabled?\n");
} else {
fprintf(stderr,
"ServerReflectionInfo rpc failed. Error code: %d, message: %s, "
"debug info: %s\n",
static_cast<int>(status.error_code()),
status.error_message().c_str(),
ctx_.debug_error_string().c_str());
}
gpr_log(GPR_INFO,
"ServerReflectionInfo rpc failed. Error code: %d, details: %s",
static_cast<int>(status.error_code()),
status.error_message().c_str());
}
}
}

@ -12,7 +12,7 @@ and tests run by Kokoro CI.
- See [Installing Bazel](https://docs.bazel.build/versions/master/install.html) for instructions how to install bazel on your system.
- Setup application default credentials for running remote builds by following [RBE Credentials Setup](https://cloud.google.com/remote-build-execution/docs/getting-started#set_credentials)
- Setup application default credentials for running remote builds by following ["Set credentials" section.](https://cloud.google.com/remote-build-execution/docs/set-up/first-remote-build)
## Running remote build manually from dev workstation
@ -29,5 +29,11 @@ Sanitizer runs (asan, msan, tsan, ubsan):
bazel --bazelrc=tools/remote_build/manual.bazelrc test --config=asan //test/...
```
Run on Windows MSVC:
```
# local manual run only for C++ targets (RBE to be supported)
bazel --bazelrc=tools/remote_build/windows.bazelrc test //test/cpp/...
```
Available command line options can be found in
[Bazel command line reference](https://docs.bazel.build/versions/master/command-line-reference.html)

@ -0,0 +1,3 @@
# TODO(yfen): Merge with rbe_common.bazelrc and enable Windows RBE
build --test_tag_filters=-no_windows
build --build_tag_filters=-no_windows
Loading…
Cancel
Save