diff --git a/MODULE.bazel b/MODULE.bazel index 88f3a524060..e62ec70dda0 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -2,7 +2,7 @@ module( name = "grpc-java", compatibility_level = 0, repo_name = "io_grpc_grpc_java", - version = "1.72.0-SNAPSHOT", # CURRENT_GRPC_VERSION + version = "1.72.1-SNAPSHOT", # CURRENT_GRPC_VERSION ) # GRPC_DEPS_START diff --git a/README.md b/README.md index 756519d0ad0..d1b4d516f74 100644 --- a/README.md +++ b/README.md @@ -44,8 +44,8 @@ For a guided tour, take a look at the [quick start guide](https://grpc.io/docs/languages/java/quickstart) or the more explanatory [gRPC basics](https://grpc.io/docs/languages/java/basics). -The [examples](https://github.com/grpc/grpc-java/tree/v1.71.0/examples) and the -[Android example](https://github.com/grpc/grpc-java/tree/v1.71.0/examples/android) +The [examples](https://github.com/grpc/grpc-java/tree/v1.72.0/examples) and the +[Android example](https://github.com/grpc/grpc-java/tree/v1.72.0/examples/android) are standalone projects that showcase the usage of gRPC. Download @@ -56,18 +56,18 @@ Download [the JARs][]. Or for Maven with non-Android, add to your `pom.xml`: <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-netty-shaded</artifactId> - <version>1.71.0</version> + <version>1.72.0</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-protobuf</artifactId> - <version>1.71.0</version> + <version>1.72.0</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-stub</artifactId> - <version>1.71.0</version> + <version>1.72.0</version> </dependency> <dependency> <!-- necessary for Java 9+ --> <groupId>org.apache.tomcat</groupId> @@ -79,18 +79,18 @@ Download [the JARs][]. Or for Maven with non-Android, add to your `pom.xml`: Or for Gradle with non-Android, add to your dependencies: ```gradle -runtimeOnly 'io.grpc:grpc-netty-shaded:1.71.0' -implementation 'io.grpc:grpc-protobuf:1.71.0' -implementation 'io.grpc:grpc-stub:1.71.0' +runtimeOnly 'io.grpc:grpc-netty-shaded:1.72.0' +implementation 'io.grpc:grpc-protobuf:1.72.0' +implementation 'io.grpc:grpc-stub:1.72.0' compileOnly 'org.apache.tomcat:annotations-api:6.0.53' // necessary for Java 9+ ``` For Android client, use `grpc-okhttp` instead of `grpc-netty-shaded` and `grpc-protobuf-lite` instead of `grpc-protobuf`: ```gradle -implementation 'io.grpc:grpc-okhttp:1.71.0' -implementation 'io.grpc:grpc-protobuf-lite:1.71.0' -implementation 'io.grpc:grpc-stub:1.71.0' +implementation 'io.grpc:grpc-okhttp:1.72.0' +implementation 'io.grpc:grpc-protobuf-lite:1.72.0' +implementation 'io.grpc:grpc-stub:1.72.0' compileOnly 'org.apache.tomcat:annotations-api:6.0.53' // necessary for Java 9+ ``` @@ -99,7 +99,7 @@ For [Bazel](https://bazel.build), you can either (with the GAVs from above), or use `@io_grpc_grpc_java//api` et al (see below). [the JARs]: -https://search.maven.org/search?q=g:io.grpc%20AND%20v:1.71.0 +https://search.maven.org/search?q=g:io.grpc%20AND%20v:1.72.0 Development snapshots are available in [Sonatypes's snapshot repository](https://oss.sonatype.org/content/repositories/snapshots/). @@ -131,7 +131,7 @@ For protobuf-based codegen integrated with the Maven build system, you can use <configuration> <protocArtifact>com.google.protobuf:protoc:3.25.5:exe:${os.detected.classifier}</protocArtifact> <pluginId>grpc-java</pluginId> - <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.71.0:exe:${os.detected.classifier}</pluginArtifact> + <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.72.0:exe:${os.detected.classifier}</pluginArtifact> </configuration> <executions> <execution> @@ -161,7 +161,7 @@ protobuf { } plugins { grpc { - artifact = 'io.grpc:protoc-gen-grpc-java:1.71.0' + artifact = 'io.grpc:protoc-gen-grpc-java:1.72.0' } } generateProtoTasks { @@ -194,7 +194,7 @@ protobuf { } plugins { grpc { - artifact = 'io.grpc:protoc-gen-grpc-java:1.71.0' + artifact = 'io.grpc:protoc-gen-grpc-java:1.72.0' } } generateProtoTasks { diff --git a/build.gradle b/build.gradle index 93ce60054bc..e63e03d22d2 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ subprojects { apply plugin: "net.ltgt.errorprone" group = "io.grpc" - version = "1.72.0-SNAPSHOT" // CURRENT_GRPC_VERSION + version = "1.72.1-SNAPSHOT" // CURRENT_GRPC_VERSION repositories { maven { // The google mirror is less flaky than mavenCentral() diff --git a/compiler/src/test/golden/TestDeprecatedService.java.txt b/compiler/src/test/golden/TestDeprecatedService.java.txt index 82fe6a81d18..44d4dc93175 100644 --- a/compiler/src/test/golden/TestDeprecatedService.java.txt +++ b/compiler/src/test/golden/TestDeprecatedService.java.txt @@ -8,7 +8,7 @@ import static io.grpc.MethodDescriptor.generateFullMethodName; * </pre> */ @javax.annotation.Generated( - value = "by gRPC proto compiler (version 1.72.0-SNAPSHOT)", + value = "by gRPC proto compiler (version 1.72.1-SNAPSHOT)", comments = "Source: grpc/testing/compiler/test.proto") @io.grpc.stub.annotations.GrpcGenerated @java.lang.Deprecated diff --git a/compiler/src/test/golden/TestService.java.txt b/compiler/src/test/golden/TestService.java.txt index 912bd50da12..085ba3abe46 100644 --- a/compiler/src/test/golden/TestService.java.txt +++ b/compiler/src/test/golden/TestService.java.txt @@ -8,7 +8,7 @@ import static io.grpc.MethodDescriptor.generateFullMethodName; * </pre> */ @javax.annotation.Generated( - value = "by gRPC proto compiler (version 1.72.0-SNAPSHOT)", + value = "by gRPC proto compiler (version 1.72.1-SNAPSHOT)", comments = "Source: grpc/testing/compiler/test.proto") @io.grpc.stub.annotations.GrpcGenerated public final class TestServiceGrpc { diff --git a/core/src/main/java/io/grpc/internal/DelayedClientTransport.java b/core/src/main/java/io/grpc/internal/DelayedClientTransport.java index 8ff755af3eb..eccd8fadc8c 100644 --- a/core/src/main/java/io/grpc/internal/DelayedClientTransport.java +++ b/core/src/main/java/io/grpc/internal/DelayedClientTransport.java @@ -325,7 +325,11 @@ final void reprocess(@Nullable SubchannelPicker picker) { if (!hasPendingStreams()) { return; } - pendingStreams.removeAll(toRemove); + // Avoid pendingStreams.removeAll() as it can degrade to calling toRemove.contains() for each + // element in pendingStreams. + for (PendingStream stream : toRemove) { + pendingStreams.remove(stream); + } // Because delayed transport is long-lived, we take this opportunity to down-size the // hashmap. if (pendingStreams.isEmpty()) { diff --git a/core/src/main/java/io/grpc/internal/GrpcUtil.java b/core/src/main/java/io/grpc/internal/GrpcUtil.java index 937854ac3ff..fef4b638941 100644 --- a/core/src/main/java/io/grpc/internal/GrpcUtil.java +++ b/core/src/main/java/io/grpc/internal/GrpcUtil.java @@ -219,7 +219,7 @@ public byte[] parseAsciiString(byte[] serialized) { public static final Splitter ACCEPT_ENCODING_SPLITTER = Splitter.on(',').trimResults(); - public static final String IMPLEMENTATION_VERSION = "1.72.0-SNAPSHOT"; // CURRENT_GRPC_VERSION + public static final String IMPLEMENTATION_VERSION = "1.72.1-SNAPSHOT"; // CURRENT_GRPC_VERSION /** * The default timeout in nanos for a keepalive ping request. diff --git a/examples/MODULE.bazel b/examples/MODULE.bazel index 4d72ae9c395..3612ec2640c 100644 --- a/examples/MODULE.bazel +++ b/examples/MODULE.bazel @@ -1,5 +1,5 @@ bazel_dep(name = "googleapis", repo_name = "com_google_googleapis", version = "0.0.0-20240326-1c8d509c5") -bazel_dep(name = "grpc-java", repo_name = "io_grpc_grpc_java", version = "1.72.0-SNAPSHOT") # CURRENT_GRPC_VERSION +bazel_dep(name = "grpc-java", repo_name = "io_grpc_grpc_java", version = "1.72.1-SNAPSHOT") # CURRENT_GRPC_VERSION bazel_dep(name = "grpc-proto", repo_name = "io_grpc_grpc_proto", version = "0.0.0-20240627-ec30f58") bazel_dep(name = "protobuf", repo_name = "com_google_protobuf", version = "23.1") bazel_dep(name = "rules_jvm_external", version = "6.0") diff --git a/examples/android/clientcache/app/build.gradle b/examples/android/clientcache/app/build.gradle index 1f2a17ae6bb..f68e4b52061 100644 --- a/examples/android/clientcache/app/build.gradle +++ b/examples/android/clientcache/app/build.gradle @@ -34,7 +34,7 @@ android { protobuf { protoc { artifact = 'com.google.protobuf:protoc:3.25.1' } plugins { - grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION + grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION } } generateProtoTasks { @@ -54,12 +54,12 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.0.0' // You need to build grpc-java to obtain these libraries below. - implementation 'io.grpc:grpc-okhttp:1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-protobuf-lite:1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-stub:1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-okhttp:1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-protobuf-lite:1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-stub:1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION implementation 'org.apache.tomcat:annotations-api:6.0.53' testImplementation 'junit:junit:4.13.2' testImplementation 'com.google.truth:truth:1.1.5' - testImplementation 'io.grpc:grpc-testing:1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION + testImplementation 'io.grpc:grpc-testing:1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION } diff --git a/examples/android/helloworld/app/build.gradle b/examples/android/helloworld/app/build.gradle index 09b994a4954..5ff4fa926b9 100644 --- a/examples/android/helloworld/app/build.gradle +++ b/examples/android/helloworld/app/build.gradle @@ -32,7 +32,7 @@ android { protobuf { protoc { artifact = 'com.google.protobuf:protoc:3.25.1' } plugins { - grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION + grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION } } generateProtoTasks { @@ -52,8 +52,8 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.0.0' // You need to build grpc-java to obtain these libraries below. - implementation 'io.grpc:grpc-okhttp:1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-protobuf-lite:1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-stub:1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-okhttp:1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-protobuf-lite:1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-stub:1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION implementation 'org.apache.tomcat:annotations-api:6.0.53' } diff --git a/examples/android/routeguide/app/build.gradle b/examples/android/routeguide/app/build.gradle index bdad129845b..1ae9ca28e08 100644 --- a/examples/android/routeguide/app/build.gradle +++ b/examples/android/routeguide/app/build.gradle @@ -32,7 +32,7 @@ android { protobuf { protoc { artifact = 'com.google.protobuf:protoc:3.25.1' } plugins { - grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION + grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION } } generateProtoTasks { @@ -52,8 +52,8 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.0.0' // You need to build grpc-java to obtain these libraries below. - implementation 'io.grpc:grpc-okhttp:1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-protobuf-lite:1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-stub:1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-okhttp:1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-protobuf-lite:1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-stub:1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION implementation 'org.apache.tomcat:annotations-api:6.0.53' } diff --git a/examples/android/strictmode/app/build.gradle b/examples/android/strictmode/app/build.gradle index f38110a741b..0e4a057675e 100644 --- a/examples/android/strictmode/app/build.gradle +++ b/examples/android/strictmode/app/build.gradle @@ -33,7 +33,7 @@ android { protobuf { protoc { artifact = 'com.google.protobuf:protoc:3.25.1' } plugins { - grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION + grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION } } generateProtoTasks { @@ -53,8 +53,8 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.0.0' // You need to build grpc-java to obtain these libraries below. - implementation 'io.grpc:grpc-okhttp:1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-protobuf-lite:1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-stub:1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-okhttp:1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-protobuf-lite:1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-stub:1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION implementation 'org.apache.tomcat:annotations-api:6.0.53' } diff --git a/examples/build.gradle b/examples/build.gradle index e807d09f407..8dc8cb39716 100644 --- a/examples/build.gradle +++ b/examples/build.gradle @@ -21,7 +21,7 @@ java { // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION def protobufVersion = '3.25.5' def protocVersion = protobufVersion diff --git a/examples/example-alts/build.gradle b/examples/example-alts/build.gradle index e7142f3fb5a..369f7b212da 100644 --- a/examples/example-alts/build.gradle +++ b/examples/example-alts/build.gradle @@ -21,7 +21,7 @@ java { // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION def protocVersion = '3.25.5' dependencies { diff --git a/examples/example-debug/build.gradle b/examples/example-debug/build.gradle index 1d07a7cb8ec..aa13f55d7b7 100644 --- a/examples/example-debug/build.gradle +++ b/examples/example-debug/build.gradle @@ -23,7 +23,7 @@ java { // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION def protobufVersion = '3.25.5' dependencies { diff --git a/examples/example-debug/pom.xml b/examples/example-debug/pom.xml index 00fdecdb6c4..6807df43771 100644 --- a/examples/example-debug/pom.xml +++ b/examples/example-debug/pom.xml @@ -6,13 +6,13 @@ <packaging>jar</packaging> <!-- Feel free to delete the comment at the end of these lines. It is just for safely updating the version in our release process. --> - <version>1.72.0-SNAPSHOT</version><!-- CURRENT_GRPC_VERSION --> + <version>1.72.1-SNAPSHOT</version><!-- CURRENT_GRPC_VERSION --> <name>example-debug</name> <url>https://github.com/grpc/grpc-java</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - <grpc.version>1.72.0-SNAPSHOT</grpc.version><!-- CURRENT_GRPC_VERSION --> + <grpc.version>1.72.1-SNAPSHOT</grpc.version><!-- CURRENT_GRPC_VERSION --> <protoc.version>3.25.5</protoc.version> <!-- required for jdk9 --> <maven.compiler.source>1.8</maven.compiler.source> diff --git a/examples/example-dualstack/build.gradle b/examples/example-dualstack/build.gradle index b73902095a1..b8e8ec5acc4 100644 --- a/examples/example-dualstack/build.gradle +++ b/examples/example-dualstack/build.gradle @@ -23,7 +23,7 @@ java { // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION def protobufVersion = '3.25.5' dependencies { diff --git a/examples/example-dualstack/pom.xml b/examples/example-dualstack/pom.xml index 28539851934..8ed41f27256 100644 --- a/examples/example-dualstack/pom.xml +++ b/examples/example-dualstack/pom.xml @@ -6,13 +6,13 @@ <packaging>jar</packaging> <!-- Feel free to delete the comment at the end of these lines. It is just for safely updating the version in our release process. --> - <version>1.72.0-SNAPSHOT</version><!-- CURRENT_GRPC_VERSION --> + <version>1.72.1-SNAPSHOT</version><!-- CURRENT_GRPC_VERSION --> <name>example-dualstack</name> <url>https://github.com/grpc/grpc-java</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - <grpc.version>1.72.0-SNAPSHOT</grpc.version><!-- CURRENT_GRPC_VERSION --> + <grpc.version>1.72.1-SNAPSHOT</grpc.version><!-- CURRENT_GRPC_VERSION --> <protoc.version>3.25.5</protoc.version> <!-- required for jdk9 --> <maven.compiler.source>1.8</maven.compiler.source> diff --git a/examples/example-gauth/build.gradle b/examples/example-gauth/build.gradle index 0ef0dcaefe2..f4dcf3fb8ce 100644 --- a/examples/example-gauth/build.gradle +++ b/examples/example-gauth/build.gradle @@ -21,7 +21,7 @@ java { // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION def protobufVersion = '3.25.5' def protocVersion = protobufVersion diff --git a/examples/example-gauth/pom.xml b/examples/example-gauth/pom.xml index d2a32578550..527916af157 100644 --- a/examples/example-gauth/pom.xml +++ b/examples/example-gauth/pom.xml @@ -6,13 +6,13 @@ <packaging>jar</packaging> <!-- Feel free to delete the comment at the end of these lines. It is just for safely updating the version in our release process. --> - <version>1.72.0-SNAPSHOT</version><!-- CURRENT_GRPC_VERSION --> + <version>1.72.1-SNAPSHOT</version><!-- CURRENT_GRPC_VERSION --> <name>example-gauth</name> <url>https://github.com/grpc/grpc-java</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - <grpc.version>1.72.0-SNAPSHOT</grpc.version><!-- CURRENT_GRPC_VERSION --> + <grpc.version>1.72.1-SNAPSHOT</grpc.version><!-- CURRENT_GRPC_VERSION --> <protobuf.version>3.25.5</protobuf.version> <!-- required for jdk9 --> <maven.compiler.source>1.8</maven.compiler.source> diff --git a/examples/example-gcp-csm-observability/build.gradle b/examples/example-gcp-csm-observability/build.gradle index e16e32e3bc1..c0062d69efd 100644 --- a/examples/example-gcp-csm-observability/build.gradle +++ b/examples/example-gcp-csm-observability/build.gradle @@ -22,7 +22,7 @@ java { // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION def protocVersion = '3.25.5' def openTelemetryVersion = '1.40.0' def openTelemetryPrometheusVersion = '1.40.0-alpha' diff --git a/examples/example-gcp-observability/build.gradle b/examples/example-gcp-observability/build.gradle index 1cad10bbb87..85703711527 100644 --- a/examples/example-gcp-observability/build.gradle +++ b/examples/example-gcp-observability/build.gradle @@ -22,7 +22,7 @@ java { // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION def protocVersion = '3.25.5' dependencies { diff --git a/examples/example-hostname/build.gradle b/examples/example-hostname/build.gradle index 86aa42f8ed0..3676c3ea850 100644 --- a/examples/example-hostname/build.gradle +++ b/examples/example-hostname/build.gradle @@ -21,7 +21,7 @@ java { // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION def protobufVersion = '3.25.5' dependencies { diff --git a/examples/example-hostname/pom.xml b/examples/example-hostname/pom.xml index 6993c40a1ac..46644f3ee7c 100644 --- a/examples/example-hostname/pom.xml +++ b/examples/example-hostname/pom.xml @@ -6,13 +6,13 @@ <packaging>jar</packaging> <!-- Feel free to delete the comment at the end of these lines. It is just for safely updating the version in our release process. --> - <version>1.72.0-SNAPSHOT</version><!-- CURRENT_GRPC_VERSION --> + <version>1.72.1-SNAPSHOT</version><!-- CURRENT_GRPC_VERSION --> <name>example-hostname</name> <url>https://github.com/grpc/grpc-java</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - <grpc.version>1.72.0-SNAPSHOT</grpc.version><!-- CURRENT_GRPC_VERSION --> + <grpc.version>1.72.1-SNAPSHOT</grpc.version><!-- CURRENT_GRPC_VERSION --> <protoc.version>3.25.5</protoc.version> <!-- required for jdk9 --> <maven.compiler.source>1.8</maven.compiler.source> diff --git a/examples/example-jwt-auth/build.gradle b/examples/example-jwt-auth/build.gradle index ca12c3f7872..2382365fd82 100644 --- a/examples/example-jwt-auth/build.gradle +++ b/examples/example-jwt-auth/build.gradle @@ -21,7 +21,7 @@ java { // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION def protobufVersion = '3.25.5' def protocVersion = protobufVersion diff --git a/examples/example-jwt-auth/pom.xml b/examples/example-jwt-auth/pom.xml index 7e9a915bfbd..a92e1c96dd2 100644 --- a/examples/example-jwt-auth/pom.xml +++ b/examples/example-jwt-auth/pom.xml @@ -7,13 +7,13 @@ <packaging>jar</packaging> <!-- Feel free to delete the comment at the end of these lines. It is just for safely updating the version in our release process. --> - <version>1.72.0-SNAPSHOT</version><!-- CURRENT_GRPC_VERSION --> + <version>1.72.1-SNAPSHOT</version><!-- CURRENT_GRPC_VERSION --> <name>example-jwt-auth</name> <url>https://github.com/grpc/grpc-java</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - <grpc.version>1.72.0-SNAPSHOT</grpc.version><!-- CURRENT_GRPC_VERSION --> + <grpc.version>1.72.1-SNAPSHOT</grpc.version><!-- CURRENT_GRPC_VERSION --> <protobuf.version>3.25.5</protobuf.version> <protoc.version>3.25.5</protoc.version> <!-- required for jdk9 --> diff --git a/examples/example-oauth/build.gradle b/examples/example-oauth/build.gradle index 6d06f097ccb..d2e1654f0f8 100644 --- a/examples/example-oauth/build.gradle +++ b/examples/example-oauth/build.gradle @@ -21,7 +21,7 @@ java { // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION def protobufVersion = '3.25.5' def protocVersion = protobufVersion diff --git a/examples/example-oauth/pom.xml b/examples/example-oauth/pom.xml index a9fea928a34..17514f95116 100644 --- a/examples/example-oauth/pom.xml +++ b/examples/example-oauth/pom.xml @@ -7,13 +7,13 @@ <packaging>jar</packaging> <!-- Feel free to delete the comment at the end of these lines. It is just for safely updating the version in our release process. --> - <version>1.72.0-SNAPSHOT</version><!-- CURRENT_GRPC_VERSION --> + <version>1.72.1-SNAPSHOT</version><!-- CURRENT_GRPC_VERSION --> <name>example-oauth</name> <url>https://github.com/grpc/grpc-java</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - <grpc.version>1.72.0-SNAPSHOT</grpc.version><!-- CURRENT_GRPC_VERSION --> + <grpc.version>1.72.1-SNAPSHOT</grpc.version><!-- CURRENT_GRPC_VERSION --> <protobuf.version>3.25.5</protobuf.version> <protoc.version>3.25.5</protoc.version> <!-- required for jdk9 --> diff --git a/examples/example-opentelemetry/build.gradle b/examples/example-opentelemetry/build.gradle index f575d24d19b..b4b78461812 100644 --- a/examples/example-opentelemetry/build.gradle +++ b/examples/example-opentelemetry/build.gradle @@ -21,7 +21,7 @@ java { // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION def protocVersion = '3.25.5' def openTelemetryVersion = '1.40.0' def openTelemetryPrometheusVersion = '1.40.0-alpha' diff --git a/examples/example-orca/build.gradle b/examples/example-orca/build.gradle index 45235fa1e08..3944e451403 100644 --- a/examples/example-orca/build.gradle +++ b/examples/example-orca/build.gradle @@ -16,7 +16,7 @@ java { targetCompatibility = JavaVersion.VERSION_1_8 } -def grpcVersion = '1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION def protocVersion = '3.25.5' dependencies { diff --git a/examples/example-reflection/build.gradle b/examples/example-reflection/build.gradle index ad68e891436..9dcbbd6c354 100644 --- a/examples/example-reflection/build.gradle +++ b/examples/example-reflection/build.gradle @@ -16,7 +16,7 @@ java { targetCompatibility = JavaVersion.VERSION_1_8 } -def grpcVersion = '1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION def protocVersion = '3.25.5' dependencies { diff --git a/examples/example-servlet/build.gradle b/examples/example-servlet/build.gradle index 2176df5afc5..da4a8744da1 100644 --- a/examples/example-servlet/build.gradle +++ b/examples/example-servlet/build.gradle @@ -15,7 +15,7 @@ java { targetCompatibility = JavaVersion.VERSION_1_8 } -def grpcVersion = '1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION def protocVersion = '3.25.5' dependencies { diff --git a/examples/example-tls/build.gradle b/examples/example-tls/build.gradle index e741bfe1c3f..49f0383b49a 100644 --- a/examples/example-tls/build.gradle +++ b/examples/example-tls/build.gradle @@ -21,7 +21,7 @@ java { // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION def protocVersion = '3.25.5' dependencies { diff --git a/examples/example-tls/pom.xml b/examples/example-tls/pom.xml index de9298cf0e1..93095aa01d9 100644 --- a/examples/example-tls/pom.xml +++ b/examples/example-tls/pom.xml @@ -6,13 +6,13 @@ <packaging>jar</packaging> <!-- Feel free to delete the comment at the end of these lines. It is just for safely updating the version in our release process. --> - <version>1.72.0-SNAPSHOT</version><!-- CURRENT_GRPC_VERSION --> + <version>1.72.1-SNAPSHOT</version><!-- CURRENT_GRPC_VERSION --> <name>example-tls</name> <url>https://github.com/grpc/grpc-java</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - <grpc.version>1.72.0-SNAPSHOT</grpc.version><!-- CURRENT_GRPC_VERSION --> + <grpc.version>1.72.1-SNAPSHOT</grpc.version><!-- CURRENT_GRPC_VERSION --> <protoc.version>3.25.5</protoc.version> <!-- required for jdk9 --> <maven.compiler.source>1.8</maven.compiler.source> diff --git a/examples/example-xds/build.gradle b/examples/example-xds/build.gradle index c0159dce258..16a85758c9d 100644 --- a/examples/example-xds/build.gradle +++ b/examples/example-xds/build.gradle @@ -21,7 +21,7 @@ java { // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.72.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.72.1-SNAPSHOT' // CURRENT_GRPC_VERSION def protocVersion = '3.25.5' dependencies { diff --git a/examples/pom.xml b/examples/pom.xml index edc9c4cda14..ac60626c578 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -6,13 +6,13 @@ <packaging>jar</packaging> <!-- Feel free to delete the comment at the end of these lines. It is just for safely updating the version in our release process. --> - <version>1.72.0-SNAPSHOT</version><!-- CURRENT_GRPC_VERSION --> + <version>1.72.1-SNAPSHOT</version><!-- CURRENT_GRPC_VERSION --> <name>examples</name> <url>https://github.com/grpc/grpc-java</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - <grpc.version>1.72.0-SNAPSHOT</grpc.version><!-- CURRENT_GRPC_VERSION --> + <grpc.version>1.72.1-SNAPSHOT</grpc.version><!-- CURRENT_GRPC_VERSION --> <protobuf.version>3.25.5</protobuf.version> <protoc.version>3.25.5</protoc.version> <!-- required for JDK 8 --> diff --git a/stub/src/main/java/io/grpc/stub/ServerCalls.java b/stub/src/main/java/io/grpc/stub/ServerCalls.java index 7990a5b34c0..9f0063713cc 100644 --- a/stub/src/main/java/io/grpc/stub/ServerCalls.java +++ b/stub/src/main/java/io/grpc/stub/ServerCalls.java @@ -382,9 +382,10 @@ public void onNext(RespT response) { @Override public void onError(Throwable t) { - Metadata metadata = Status.trailersFromThrowable(t); - if (metadata == null) { - metadata = new Metadata(); + Metadata metadata = new Metadata(); + Metadata trailers = Status.trailersFromThrowable(t); + if (trailers != null) { + metadata.merge(trailers); } call.close(Status.fromThrowable(t), metadata); aborted = true; diff --git a/stub/src/main/java/io/grpc/stub/StreamObservers.java b/stub/src/main/java/io/grpc/stub/StreamObservers.java index 2cc53ea0aa2..a421d3eca2f 100644 --- a/stub/src/main/java/io/grpc/stub/StreamObservers.java +++ b/stub/src/main/java/io/grpc/stub/StreamObservers.java @@ -23,12 +23,21 @@ /** * Utility functions for working with {@link StreamObserver} and it's common subclasses like * {@link CallStreamObserver}. - * - * @deprecated Of questionable utility and generally not used. */ -@Deprecated -@ExperimentalApi("https://github.com/grpc/grpc-java/issues/4694") public final class StreamObservers { + // Prevent instantiation + private StreamObservers() { } + + /** + * Utility method to call {@link StreamObserver#onNext(Object)} and + * {@link StreamObserver#onCompleted()} on the specified responseObserver. + */ + @ExperimentalApi("https://github.com/grpc/grpc-java/issues/10957") + public static <T> void nextAndComplete(StreamObserver<T> responseObserver, T response) { + responseObserver.onNext(response); + responseObserver.onCompleted(); + } + /** * Copy the values of an {@link Iterator} to the target {@link CallStreamObserver} while properly * accounting for outbound flow-control. After calling this method, {@code target} should no @@ -40,7 +49,10 @@ public final class StreamObservers { * * @param source of values expressed as an {@link Iterator}. * @param target {@link CallStreamObserver} which accepts values from the source. + * @deprecated Of questionable utility and generally not used. */ + @Deprecated + @ExperimentalApi("https://github.com/grpc/grpc-java/issues/4694") public static <V> void copyWithFlowControl(final Iterator<V> source, final CallStreamObserver<V> target) { Preconditions.checkNotNull(source, "source"); @@ -80,7 +92,10 @@ public void run() { * * @param source of values expressed as an {@link Iterable}. * @param target {@link CallStreamObserver} which accepts values from the source. + * @deprecated Of questionable utility and generally not used. */ + @Deprecated + @ExperimentalApi("https://github.com/grpc/grpc-java/issues/4694") public static <V> void copyWithFlowControl(final Iterable<V> source, CallStreamObserver<V> target) { Preconditions.checkNotNull(source, "source"); diff --git a/stub/src/test/java/io/grpc/stub/ServerCallsTest.java b/stub/src/test/java/io/grpc/stub/ServerCallsTest.java index 1e51ac10110..6f458facc5e 100644 --- a/stub/src/test/java/io/grpc/stub/ServerCallsTest.java +++ b/stub/src/test/java/io/grpc/stub/ServerCallsTest.java @@ -555,6 +555,35 @@ public void invoke(Integer req, StreamObserver<Integer> responseObserver) { listener.onHalfClose(); } + @Test + public void clientSendsOne_serverOnErrorWithTrailers_serverStreaming() { + Metadata trailers = new Metadata(); + Metadata.Key<String> key = Metadata.Key.of("trailers-test-key1", + Metadata.ASCII_STRING_MARSHALLER); + trailers.put(key, "trailers-test-value1"); + + ServerCallRecorder serverCall = new ServerCallRecorder(SERVER_STREAMING_METHOD); + ServerCallHandler<Integer, Integer> callHandler = ServerCalls.asyncServerStreamingCall( + new ServerCalls.ServerStreamingMethod<Integer, Integer>() { + @Override + public void invoke(Integer req, StreamObserver<Integer> responseObserver) { + responseObserver.onError( + Status.fromCode(Status.Code.INTERNAL) + .asRuntimeException(trailers) + ); + } + }); + ServerCall.Listener<Integer> listener = callHandler.startCall(serverCall, new Metadata()); + serverCall.isReady = true; + serverCall.isCancelled = false; + listener.onReady(); + listener.onMessage(1); + listener.onHalfClose(); + // verify trailers key is set + assertTrue(serverCall.trailers.containsKey(key)); + assertTrue(serverCall.status.equals(Status.INTERNAL)); + } + @Test public void inprocessTransportManualFlow() throws Exception { final Semaphore semaphore = new Semaphore(1); @@ -652,6 +681,7 @@ private static class ServerCallRecorder extends ServerCall<Integer, Integer> { private boolean isCancelled; private boolean isReady; private int onReadyThreshold; + private Metadata trailers; public ServerCallRecorder(MethodDescriptor<Integer, Integer> methodDescriptor) { this.methodDescriptor = methodDescriptor; @@ -674,6 +704,7 @@ public void sendMessage(Integer message) { @Override public void close(Status status, Metadata trailers) { this.status = status; + this.trailers = trailers; } @Override diff --git a/stub/src/test/java/io/grpc/stub/StreamObserversTest.java b/stub/src/test/java/io/grpc/stub/StreamObserversTest.java new file mode 100644 index 00000000000..86a1aba2e76 --- /dev/null +++ b/stub/src/test/java/io/grpc/stub/StreamObserversTest.java @@ -0,0 +1,35 @@ +/* + * Copyright 2025 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. + */ + +package io.grpc.stub; + +import org.junit.Test; +import org.mockito.InOrder; +import org.mockito.Mockito; + +public class StreamObserversTest { + + @Test + public void nextAndComplete() { + @SuppressWarnings("unchecked") + StreamObserver<String> observer = Mockito.mock(StreamObserver.class); + InOrder inOrder = Mockito.inOrder(observer); + StreamObservers.nextAndComplete(observer, "TEST"); + inOrder.verify(observer).onNext("TEST"); + inOrder.verify(observer).onCompleted(); + inOrder.verifyNoMoreInteractions(); + } +} diff --git a/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancer.java b/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancer.java index c92f592ebc8..0fb7cf15909 100644 --- a/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancer.java +++ b/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancer.java @@ -33,6 +33,7 @@ import io.grpc.NameResolver; import io.grpc.NameResolver.ResolutionResult; import io.grpc.Status; +import io.grpc.StatusOr; import io.grpc.SynchronizationContext; import io.grpc.SynchronizationContext.ScheduledHandle; import io.grpc.internal.BackoffPolicy; @@ -657,79 +658,84 @@ private class NameResolverListener extends NameResolver.Listener2 { @Override public void onResult(final ResolutionResult resolutionResult) { - class NameResolved implements Runnable { - @Override - public void run() { - if (shutdown) { - return; - } - backoffPolicy = null; // reset backoff sequence if succeeded - // Arbitrary priority notation for all DNS-resolved endpoints. - String priorityName = priorityName(name, 0); // value doesn't matter - List<EquivalentAddressGroup> addresses = new ArrayList<>(); - for (EquivalentAddressGroup eag : resolutionResult.getAddresses()) { - // No weight attribute is attached, all endpoint-level LB policy should be able - // to handle such it. - String localityName = localityName(LOGICAL_DNS_CLUSTER_LOCALITY); - Attributes attr = eag.getAttributes().toBuilder() - .set(XdsAttributes.ATTR_LOCALITY, LOGICAL_DNS_CLUSTER_LOCALITY) - .set(XdsAttributes.ATTR_LOCALITY_NAME, localityName) - .set(XdsAttributes.ATTR_ADDRESS_NAME, dnsHostName) - .build(); - eag = new EquivalentAddressGroup(eag.getAddresses(), attr); - eag = AddressFilter.setPathFilter(eag, Arrays.asList(priorityName, localityName)); - addresses.add(eag); - } - PriorityChildConfig priorityChildConfig = generateDnsBasedPriorityChildConfig( - name, lrsServerInfo, maxConcurrentRequests, tlsContext, filterMetadata, - lbRegistry, Collections.<DropOverload>emptyList()); - status = Status.OK; - resolved = true; - result = new ClusterResolutionResult(addresses, priorityName, priorityChildConfig); - handleEndpointResourceUpdate(); + syncContext.execute(() -> onResult2(resolutionResult)); + } + + @Override + public Status onResult2(final ResolutionResult resolutionResult) { + if (shutdown) { + return Status.OK; + } + // Arbitrary priority notation for all DNS-resolved endpoints. + String priorityName = priorityName(name, 0); // value doesn't matter + List<EquivalentAddressGroup> addresses = new ArrayList<>(); + StatusOr<List<EquivalentAddressGroup>> addressesOrError = + resolutionResult.getAddressesOrError(); + if (addressesOrError.hasValue()) { + backoffPolicy = null; // reset backoff sequence if succeeded + for (EquivalentAddressGroup eag : resolutionResult.getAddresses()) { + // No weight attribute is attached, all endpoint-level LB policy should be able + // to handle such it. + String localityName = localityName(LOGICAL_DNS_CLUSTER_LOCALITY); + Attributes attr = eag.getAttributes().toBuilder() + .set(XdsAttributes.ATTR_LOCALITY, LOGICAL_DNS_CLUSTER_LOCALITY) + .set(XdsAttributes.ATTR_LOCALITY_NAME, localityName) + .set(XdsAttributes.ATTR_ADDRESS_NAME, dnsHostName) + .build(); + eag = new EquivalentAddressGroup(eag.getAddresses(), attr); + eag = AddressFilter.setPathFilter(eag, Arrays.asList(priorityName, localityName)); + addresses.add(eag); } + PriorityChildConfig priorityChildConfig = generateDnsBasedPriorityChildConfig( + name, lrsServerInfo, maxConcurrentRequests, tlsContext, filterMetadata, + lbRegistry, Collections.<DropOverload>emptyList()); + status = Status.OK; + resolved = true; + result = new ClusterResolutionResult(addresses, priorityName, priorityChildConfig); + handleEndpointResourceUpdate(); + return Status.OK; + } else { + handleErrorInSyncContext(addressesOrError.getStatus()); + return addressesOrError.getStatus(); } - - syncContext.execute(new NameResolved()); } @Override public void onError(final Status error) { - syncContext.execute(new Runnable() { - @Override - public void run() { - if (shutdown) { - return; - } - status = error; - // NameResolver.Listener API cannot distinguish between address-not-found and - // transient errors. If the error occurs in the first resolution, treat it as - // address not found. Otherwise, either there is previously resolved addresses - // previously encountered error, propagate the error to downstream/upstream and - // let downstream/upstream handle it. - if (!resolved) { - resolved = true; - handleEndpointResourceUpdate(); - } else { - handleEndpointResolutionError(); - } - if (scheduledRefresh != null && scheduledRefresh.isPending()) { - return; - } - if (backoffPolicy == null) { - backoffPolicy = backoffPolicyProvider.get(); - } - long delayNanos = backoffPolicy.nextBackoffNanos(); - logger.log(XdsLogLevel.DEBUG, + syncContext.execute(() -> handleErrorInSyncContext(error)); + } + + private void handleErrorInSyncContext(final Status error) { + if (shutdown) { + return; + } + status = error; + // NameResolver.Listener API cannot distinguish between address-not-found and + // transient errors. If the error occurs in the first resolution, treat it as + // address not found. Otherwise, either there is previously resolved addresses + // previously encountered error, propagate the error to downstream/upstream and + // let downstream/upstream handle it. + if (!resolved) { + resolved = true; + handleEndpointResourceUpdate(); + } else { + handleEndpointResolutionError(); + } + if (scheduledRefresh != null && scheduledRefresh.isPending()) { + return; + } + if (backoffPolicy == null) { + backoffPolicy = backoffPolicyProvider.get(); + } + long delayNanos = backoffPolicy.nextBackoffNanos(); + logger.log(XdsLogLevel.DEBUG, "Logical DNS resolver for cluster {0} encountered name resolution " - + "error: {1}, scheduling DNS resolution backoff for {2} ns", + + "error: {1}, scheduling DNS resolution backoff for {2} ns", name, error, delayNanos); - scheduledRefresh = + scheduledRefresh = syncContext.schedule( - new DelayedNameResolverRefresh(), delayNanos, TimeUnit.NANOSECONDS, - timeService); - } - }); + new DelayedNameResolverRefresh(), delayNanos, TimeUnit.NANOSECONDS, + timeService); } } } diff --git a/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java b/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java index d0176d7aa38..d701f281c01 100644 --- a/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java +++ b/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java @@ -200,6 +200,7 @@ public XdsClient returnObject(Object object) { private ArgumentCaptor<SubchannelPicker> pickerCaptor; private int xdsClientRefs; private ClusterResolverLoadBalancer loadBalancer; + private NameResolverProvider fakeNameResolverProvider; @Before public void setUp() throws URISyntaxException { @@ -216,7 +217,8 @@ public void setUp() throws URISyntaxException { .setServiceConfigParser(mock(ServiceConfigParser.class)) .setChannelLogger(mock(ChannelLogger.class)) .build(); - nsRegistry.register(new FakeNameResolverProvider()); + fakeNameResolverProvider = new FakeNameResolverProvider(false); + nsRegistry.register(fakeNameResolverProvider); when(helper.getNameResolverRegistry()).thenReturn(nsRegistry); when(helper.getNameResolverArgs()).thenReturn(args); when(helper.getSynchronizationContext()).thenReturn(syncContext); @@ -826,6 +828,17 @@ public void handleEdsResource_noHealthyEndpoint() { @Test public void onlyLogicalDnsCluster_endpointsResolved() { + do_onlyLogicalDnsCluster_endpointsResolved(); + } + + @Test + public void oldListenerCallback_onlyLogicalDnsCluster_endpointsResolved() { + nsRegistry.deregister(fakeNameResolverProvider); + nsRegistry.register(new FakeNameResolverProvider(true)); + do_onlyLogicalDnsCluster_endpointsResolved(); + } + + void do_onlyLogicalDnsCluster_endpointsResolved() { ClusterResolverConfig config = new ClusterResolverConfig( Collections.singletonList(logicalDnsDiscoveryMechanism), roundRobin, false); deliverLbConfig(config); @@ -854,7 +867,6 @@ public void onlyLogicalDnsCluster_endpointsResolved() { .get(XdsAttributes.ATTR_ADDRESS_NAME)).isEqualTo(DNS_HOST_NAME); assertThat(childBalancer.addresses.get(1).getAttributes() .get(XdsAttributes.ATTR_ADDRESS_NAME)).isEqualTo(DNS_HOST_NAME); - } @Test @@ -874,37 +886,48 @@ public void onlyLogicalDnsCluster_handleRefreshNameResolution() { } @Test - public void onlyLogicalDnsCluster_resolutionError_backoffAndRefresh() { + public void resolutionError_backoffAndRefresh() { + do_onlyLogicalDnsCluster_resolutionError_backoffAndRefresh(); + } + + @Test + public void oldListenerCallback_resolutionError_backoffAndRefresh() { + nsRegistry.deregister(fakeNameResolverProvider); + nsRegistry.register(new FakeNameResolverProvider(true)); + do_onlyLogicalDnsCluster_resolutionError_backoffAndRefresh(); + } + + void do_onlyLogicalDnsCluster_resolutionError_backoffAndRefresh() { InOrder inOrder = Mockito.inOrder(helper, backoffPolicyProvider, - backoffPolicy1, backoffPolicy2); + backoffPolicy1, backoffPolicy2); ClusterResolverConfig config = new ClusterResolverConfig( - Collections.singletonList(logicalDnsDiscoveryMechanism), roundRobin, false); + Collections.singletonList(logicalDnsDiscoveryMechanism), roundRobin, false); deliverLbConfig(config); FakeNameResolver resolver = assertResolverCreated("/" + DNS_HOST_NAME); assertThat(childBalancers).isEmpty(); Status error = Status.UNAVAILABLE.withDescription("cannot reach DNS server"); resolver.deliverError(error); inOrder.verify(helper).updateBalancingState( - eq(ConnectivityState.TRANSIENT_FAILURE), pickerCaptor.capture()); + eq(ConnectivityState.TRANSIENT_FAILURE), pickerCaptor.capture()); assertPicker(pickerCaptor.getValue(), error, null); assertThat(resolver.refreshCount).isEqualTo(0); inOrder.verify(backoffPolicyProvider).get(); inOrder.verify(backoffPolicy1).nextBackoffNanos(); assertThat(fakeClock.getPendingTasks()).hasSize(1); assertThat(Iterables.getOnlyElement(fakeClock.getPendingTasks()).getDelay(TimeUnit.SECONDS)) - .isEqualTo(1L); + .isEqualTo(1L); fakeClock.forwardTime(1L, TimeUnit.SECONDS); assertThat(resolver.refreshCount).isEqualTo(1); error = Status.UNKNOWN.withDescription("I am lost"); resolver.deliverError(error); inOrder.verify(helper).updateBalancingState( - eq(ConnectivityState.TRANSIENT_FAILURE), pickerCaptor.capture()); + eq(ConnectivityState.TRANSIENT_FAILURE), pickerCaptor.capture()); inOrder.verify(backoffPolicy1).nextBackoffNanos(); assertPicker(pickerCaptor.getValue(), error, null); assertThat(fakeClock.getPendingTasks()).hasSize(1); assertThat(Iterables.getOnlyElement(fakeClock.getPendingTasks()).getDelay(TimeUnit.SECONDS)) - .isEqualTo(10L); + .isEqualTo(10L); fakeClock.forwardTime(10L, TimeUnit.SECONDS); assertThat(resolver.refreshCount).isEqualTo(2); @@ -914,7 +937,7 @@ public void onlyLogicalDnsCluster_resolutionError_backoffAndRefresh() { resolver.deliverEndpointAddresses(Arrays.asList(endpoint1, endpoint2)); assertThat(childBalancers).hasSize(1); assertAddressesEqual(Arrays.asList(endpoint1, endpoint2), - Iterables.getOnlyElement(childBalancers).addresses); + Iterables.getOnlyElement(childBalancers).addresses); assertThat(fakeClock.getPendingTasks()).isEmpty(); inOrder.verifyNoMoreInteractions(); @@ -1319,10 +1342,18 @@ void deliverError(Status error) { } private class FakeNameResolverProvider extends NameResolverProvider { + private final boolean useOldListenerCallback; + + private FakeNameResolverProvider(boolean useOldListenerCallback) { + this.useOldListenerCallback = useOldListenerCallback; + } + @Override public NameResolver newNameResolver(URI targetUri, NameResolver.Args args) { assertThat(targetUri.getScheme()).isEqualTo("dns"); - FakeNameResolver resolver = new FakeNameResolver(targetUri); + FakeNameResolver resolver = useOldListenerCallback + ? new FakeNameResolverUsingOldListenerCallback(targetUri) + : new FakeNameResolver(targetUri); resolvers.add(resolver); return resolver; } @@ -1343,9 +1374,10 @@ protected int priority() { } } + private class FakeNameResolver extends NameResolver { private final URI targetUri; - private Listener2 listener; + protected Listener2 listener; private int refreshCount; private FakeNameResolver(URI targetUri) { @@ -1372,12 +1404,33 @@ public void shutdown() { resolvers.remove(this); } - private void deliverEndpointAddresses(List<EquivalentAddressGroup> addresses) { + protected void deliverEndpointAddresses(List<EquivalentAddressGroup> addresses) { + syncContext.execute(() -> { + Status ret = listener.onResult2(ResolutionResult.newBuilder() + .setAddressesOrError(StatusOr.fromValue(addresses)).build()); + assertThat(ret.getCode()).isEqualTo(Status.Code.OK); + }); + } + + protected void deliverError(Status error) { + syncContext.execute(() -> listener.onResult2(ResolutionResult.newBuilder() + .setAddressesOrError(StatusOr.fromStatus(error)).build())); + } + } + + private class FakeNameResolverUsingOldListenerCallback extends FakeNameResolver { + private FakeNameResolverUsingOldListenerCallback(URI targetUri) { + super(targetUri); + } + + @Override + protected void deliverEndpointAddresses(List<EquivalentAddressGroup> addresses) { listener.onResult(ResolutionResult.newBuilder() - .setAddressesOrError(StatusOr.fromValue(addresses)).build()); + .setAddressesOrError(StatusOr.fromValue(addresses)).build()); } - private void deliverError(Status error) { + @Override + protected void deliverError(Status error) { listener.onError(error); } }