diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index f45d2c83e..a1d58a77c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -4,4 +4,4 @@ # For syntax help see: # https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-syntax -* @googleapis/actools-java @googleapis/yoshi-java +* @googleapis/actools-java @googleapis/yoshi-java @googleapis/cloud-java-team-teamsync diff --git a/.github/release-please.yml b/.github/release-please.yml index 801cc7dbe..c01275665 100644 --- a/.github/release-please.yml +++ b/.github/release-please.yml @@ -11,4 +11,8 @@ branches: - bumpMinorPreMajor: true handleGHRelease: true releaseType: java-yoshi - branch: java7 \ No newline at end of file + branch: java7 + - releaseType: java-backport + bumpMinorPreMajor: true + handleGHRelease: true + branch: 2.6.x diff --git a/.github/sync-repo-settings.yaml b/.github/sync-repo-settings.yaml index 75b33019e..f77ddd5c2 100644 --- a/.github/sync-repo-settings.yaml +++ b/.github/sync-repo-settings.yaml @@ -51,6 +51,16 @@ branchProtectionRules: - units (8) - units (11) - cla/google + - pattern: 2.6.x + isAdminEnforced: true + requiredApprovingReviewCount: 1 + requiresCodeOwnerReviews: true + requiresStrictStatusChecks: true + requiredStatusCheckContexts: + - bazel + - units (8) + - units (11) + - cla/google permissionRules: - team: yoshi-admins permission: admin diff --git a/.gitignore b/.gitignore index b632969b5..e41705477 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,7 @@ tmp_docs bazel-* # Eclipse -.apt_generated +.apt_generated* .classpath .factorypath .project diff --git a/.kokoro/build.sh b/.kokoro/build.sh index f9c9b3f63..b386de565 100755 --- a/.kokoro/build.sh +++ b/.kokoro/build.sh @@ -23,4 +23,4 @@ cd ${scriptDir}/.. java -version echo $JOB_TYPE -./gradlew -Pskip.signing build publishToMavenLocal +./gradlew build publishToMavenLocal diff --git a/.kokoro/continuous/java7.cfg b/.kokoro/continuous/java7.cfg deleted file mode 100644 index cb24f44ee..000000000 --- a/.kokoro/continuous/java7.cfg +++ /dev/null @@ -1,7 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -# Configure the docker image for kokoro-trampoline. -env_vars: { - key: "TRAMPOLINE_IMAGE" - value: "gcr.io/cloud-devrel-kokoro-resources/java7" -} diff --git a/.kokoro/presubmit/java7.cfg b/.kokoro/presubmit/java7.cfg deleted file mode 100644 index cb24f44ee..000000000 --- a/.kokoro/presubmit/java7.cfg +++ /dev/null @@ -1,7 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -# Configure the docker image for kokoro-trampoline. -env_vars: { - key: "TRAMPOLINE_IMAGE" - value: "gcr.io/cloud-devrel-kokoro-resources/java7" -} diff --git a/CHANGELOG.md b/CHANGELOG.md index 45cdbcfa4..0515a8ff6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # Changelog +## [2.7.0](https://www.github.com/googleapis/gax-java/compare/v2.6.0...v2.7.0) (2021-11-03) + + +### Features + +* add batch throttled time to tracer ([#1463](https://www.github.com/googleapis/gax-java/issues/1463)) ([14c25cd](https://www.github.com/googleapis/gax-java/commit/14c25cdfae2c0602d99fcd07c9067138fc172a7f)) +* add google-c2p dependence to DirectPath ([#1521](https://www.github.com/googleapis/gax-java/issues/1521)) ([d4222e7](https://www.github.com/googleapis/gax-java/commit/d4222e757d35e874a57d030f2f964e8d61c71d6d)) +* next release from main branch is 2.7.0 ([#1530](https://www.github.com/googleapis/gax-java/issues/1530)) ([a96953e](https://www.github.com/googleapis/gax-java/commit/a96953e2c889ad9195b420ce5ae49b20258fb6ea)) +* pass request in ApiTracer ([#1491](https://www.github.com/googleapis/gax-java/issues/1491)) ([27bf265](https://www.github.com/googleapis/gax-java/commit/27bf2655120972d929e6118b73d8d556b0440fcf)) + + +### Bug Fixes + +* call ResponseMetadataHanlder#onTrailers before calling onClose ([#1549](https://www.github.com/googleapis/gax-java/issues/1549)) ([19a77a4](https://www.github.com/googleapis/gax-java/commit/19a77a4f6c62e84bba4879690992bbc494730d23)) +* declare depenencies of API surfaces as api ([#1535](https://www.github.com/googleapis/gax-java/issues/1535)) ([725414f](https://www.github.com/googleapis/gax-java/commit/725414f4ccb1e5ac4625790ea990c6c8dfa4fdff)) + ## [2.6.0](https://www.github.com/googleapis/gax-java/compare/v2.5.3...v2.6.0) (2021-10-15) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2cbb4303c..2ab6d62b1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -30,7 +30,7 @@ To build GAX: To install GAX into the local maven repository: ```sh -./gradlew publishToMavenLocal -Pskip.signing +./gradlew publishToMavenLocal ``` ### The small print diff --git a/README.md b/README.md index 84ea27472..0813b4d4d 100644 --- a/README.md +++ b/README.md @@ -29,27 +29,27 @@ If you are using Maven, add this to your pom.xml file com.google.api gax - 2.6.0 + 2.7.0 com.google.api gax-grpc - 2.6.0 + 2.7.0 ``` If you are using Gradle, add this to your dependencies ```Groovy -compile 'com.google.api:gax:2.6.0', - 'com.google.api:gax-grpc:2.6.0' +compile 'com.google.api:gax:2.7.0', + 'com.google.api:gax-grpc:2.7.0' ``` If you are using SBT, add this to your dependencies ```Scala -libraryDependencies += "com.google.api" % "gax" % "2.6.0" -libraryDependencies += "com.google.api" % "gax-grpc" % "2.6.0" +libraryDependencies += "com.google.api" % "gax" % "2.7.0" +libraryDependencies += "com.google.api" % "gax-grpc" % "2.7.0" ``` [//]: # ({x-version-update-end}) diff --git a/benchmark/build.gradle b/benchmark/build.gradle index d1faa36fe..6384e15fb 100644 --- a/benchmark/build.gradle +++ b/benchmark/build.gradle @@ -2,14 +2,14 @@ plugins { id 'me.champeau.gradle.jmh' version '0.5.3' } -project.version = "0.76.0" // {x-version-update:benchmark:current} +project.version = "0.77.0" // {x-version-update:benchmark:current} dependencies { implementation project(':gax') implementation project(':gax-grpc') implementation "io.grpc:grpc-netty:${libraries['version.io_grpc']}" - implementation 'com.google.api.grpc:grpc-google-cloud-bigtable-v2:2.1.4' - implementation 'com.google.api.grpc:grpc-google-cloud-pubsub-v1:1.96.6' + implementation 'com.google.api.grpc:grpc-google-cloud-bigtable-v2:2.2.0' + implementation 'com.google.api.grpc:grpc-google-cloud-pubsub-v1:1.96.7' } // Allow command line to target specific test diff --git a/build.gradle b/build.gradle index 9162df0df..849b52e46 100644 --- a/build.gradle +++ b/build.gradle @@ -4,52 +4,70 @@ plugins { id 'java' id 'io.github.gradle-nexus.publish-plugin' version '1.1.0' + id 'com.diffplug.eclipse.apt' version '3.33.1' apply false id 'com.dorongold.task-tree' version '2.1.0' apply false id 'com.github.johnrengelman.shadow' version '6.1.0' apply false id 'com.github.sherter.google-java-format' version '0.8' apply false - id 'net.ltgt.apt' version '0.21' apply false } // TODO: Populate this from dependencies.properties version property (for proper Gradle-Bazel sync) -project.version = "2.6.0" // {x-version-update:gax:current} +project.version = "2.7.0" // {x-version-update:gax:current} + +allprojects { + group = 'com.google.api' +} + +// Project names not used for release +def nonReleaseProjects = ['benchmark'] +// Project names not using the default publication configuration +def noDefaultPublications = ['benchmark', 'gax-bom'] +def nonJavaProjects = ['gax-bom'] ext { - // Project names not used for release - nonReleaseProjects = ['benchmark'] - // Project names not using the default publication configuration - noDefaultPublications = ['benchmark', 'gax-bom'] libraryVendor = 'Google' + + // Load Dependencies shared between Bazel and Gradle build scripts + libraries = new Properties() + file('dependencies.properties').withReader { libraries.load(it) } + // Gradle-specific build script dependencies + libraries.putAll( + 'maven.io_grpc_grpc_bom': "io.grpc:grpc-bom:${libraries['version.io_grpc']}", + 'maven.io_grpc_grpc_core': "io.grpc:grpc-core:${libraries['version.io_grpc']}", + 'maven.io_grpc_grpc_context': "io.grpc:grpc-context:${libraries['version.io_grpc']}", + 'maven.io_grpc_grpc_stub': "io.grpc:grpc-stub:${libraries['version.io_grpc']}", + 'maven.io_grpc_grpc_api': "io.grpc:grpc-api:${libraries['version.io_grpc']}", + 'maven.io_grpc_grpc_auth': "io.grpc:grpc-auth:${libraries['version.io_grpc']}", + 'maven.io_grpc_grpc_protobuf': "io.grpc:grpc-protobuf:${libraries['version.io_grpc']}", + 'maven.io_grpc_grpc_netty_shaded': "io.grpc:grpc-netty-shaded:${libraries['version.io_grpc']}", + 'maven.io_grpc_grpc_alts': "io.grpc:grpc-alts:${libraries['version.io_grpc']}", + 'maven.io_grpc_grpc_xds': "io.grpc:grpc-xds:${libraries['version.io_grpc']}", + 'maven.com_google_protobuf': "com.google.protobuf:protobuf-java:${libraries['version.com_google_protobuf']}", + 'maven.com_google_protobuf_java_util': "com.google.protobuf:protobuf-java-util:${libraries['version.com_google_protobuf']}") } -if (project.hasProperty('ossrhUsername') && project.hasProperty('ossrhPassword') && - !nonReleaseProjects.contains(project.name)) { - nexusPublishing { - packageGroup = 'com.google.api' - repositories { - sonatype { //or custom repository name - nexusUrl.set(uri('https://google.oss.sonatype.org/service/local/')) - snapshotRepositoryUrl.set(uri('https://google.oss.sonatype.org/content/repositories/snapshots/')) - username = ossrhUsername - password = ossrhPassword - } +nexusPublishing { + packageGroup = 'com.google.api' + repositories { + sonatype { + nexusUrl = uri('https://google.oss.sonatype.org/service/local/') + snapshotRepositoryUrl = uri('https://google.oss.sonatype.org/content/repositories/snapshots/') + username = findProperty('ossrhUsername') + password = findProperty('ossrhPassword') } } } -subprojects { - apply plugin: 'java' +def javaProjects = subprojects.findAll { !nonJavaProjects.contains(it.name) } +configure(javaProjects) { + apply plugin: 'java-library' apply plugin: 'eclipse' apply plugin: 'idea' apply plugin: 'jacoco' - apply plugin: 'maven-publish' - apply plugin: 'signing' + apply plugin: 'com.diffplug.eclipse.apt' apply plugin: 'com.dorongold.task-tree' apply plugin: 'com.github.johnrengelman.shadow' apply plugin: 'com.github.sherter.google-java-format' - apply plugin: 'net.ltgt.apt' - - group = 'com.google.api' sourceCompatibility = 1.8 targetCompatibility = 1.8 @@ -57,67 +75,40 @@ subprojects { // Formatting tasks // ================ googleJavaFormat { - exclude '.apt_generated/**' + exclude '.apt_generated*/**' exclude 'bin/**' exclude 'build/**' exclude 'bazel*/**' } - test.dependsOn verifyGoogleJavaFormat task verifyLicense { doLast { - def licenseText = new File(rootProject.rootDir, 'license-header-javadoc.txt').text + def licenseText = new File('license-header-javadoc.txt').text def srcFiles = [] sourceSets .collectMany{it.allJava.getSrcDirs()} .grep{it.exists()} .each{it.eachFileRecurse(FileType.FILES, {srcFiles << new Tuple(it, it.text)})} srcFiles = srcFiles - .findAll{it.get(0).path.endsWith(".java")} - .collect{new Tuple(it.get(0), it.get(1).replaceAll("Copyright 20[0-9]{2}", "Copyright 20xx"))} + .findAll{it.get(0).path.endsWith('.java')} + .collect{new Tuple(it.get(0), it.get(1).replaceAll('Copyright 20[0-9]{2}', 'Copyright 20xx'))} .findAll{!it.get(1).startsWith(licenseText)} if (srcFiles.asList().size() > 0) { srcFiles.each({println 'missing license: ' + it.get(0)}) - throw new IllegalStateException("Above files do not have licenses") + throw new IllegalStateException('Above files do not have licenses') } } } test.dependsOn verifyLicense - gradle.projectsEvaluated { - tasks.withType(JavaCompile) { - options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" - } + tasks.withType(JavaCompile) { + options.compilerArgs << '-Xlint:unchecked' << '-Xlint:deprecation' } // Dependencies // ------------ - jacoco { - toolVersion = "0.8.5" - } - - ext { - // Load Dependencies shared between Bazel and Gradle build scripts - libraries = new Properties() - file(new File(rootDir, "dependencies.properties")).withReader{ libraries.load((Reader) it) } - - // Gradle-specific build script dependencies - libraries.putAll([ - 'maven.io_grpc_grpc_bom': "io.grpc:grpc-bom:${libraries['version.io_grpc']}", - 'maven.io_grpc_grpc_core': "io.grpc:grpc-core:${libraries['version.io_grpc']}", - 'maven.io_grpc_grpc_context': "io.grpc:grpc-context:${libraries['version.io_grpc']}", - 'maven.io_grpc_grpc_stub': "io.grpc:grpc-stub:${libraries['version.io_grpc']}", - 'maven.io_grpc_grpc_auth': "io.grpc:grpc-auth:${libraries['version.io_grpc']}", - 'maven.io_grpc_grpc_protobuf': "io.grpc:grpc-protobuf:${libraries['version.io_grpc']}", - 'maven.io_grpc_grpc_netty_shaded': "io.grpc:grpc-netty-shaded:${libraries['version.io_grpc']}", - 'maven.io_grpc_grpc_alts': "io.grpc:grpc-alts:${libraries['version.io_grpc']}", - 'maven.com_google_protobuf': "com.google.protobuf:protobuf-java:${libraries['version.com_google_protobuf']}", - 'maven.com_google_protobuf_java_util': "com.google.protobuf:protobuf-java-util:${libraries['version.com_google_protobuf']}" - ]) - } - repositories { mavenLocal() mavenCentral() @@ -126,8 +117,15 @@ subprojects { configurations { shadowNoGuava linkageChecker + implementation.exclude group: 'com.google.guava', module: 'guava-jdk5' + } + + dependencies { + // Separate configuration (class path) for Linkage Checker + linkageChecker 'com.google.cloud.tools:dependencies:1.5.12' } + jacoco.toolVersion = '0.8.5' jacocoTestReport { reports { xml.enabled true @@ -135,12 +133,10 @@ subprojects { } afterEvaluate { getClassDirectories().setFrom files(classDirectories.files.collect { - fileTree(dir: it, - exclude: ['**/AutoValue_*']) - }) + fileTree(dir: it, exclude: ['**/AutoValue_*']) + }) } } - check.dependsOn jacocoTestReport @@ -212,159 +208,100 @@ subprojects { test { testLogging { - events "passed", "skipped", "failed", "standardOut", "standardError" + events 'passed', 'skipped', 'failed', 'standardOut', 'standardError' exceptionFormat = 'full' } } + // Eclipse annotation processing auto-setup + eclipse.synchronizationTasks eclipseJdtApt, eclipseJdt, eclipseFactorypath +} - // Eclipse Annotation Processing - // ----------------------------- - - ext { - eclipseAptFolder = '.apt_generated' - eclipseSettingsDir = file('.settings') - } - - configurations { - codeGeneration - implementation.exclude group: 'com.google.guava', module: 'guava-jdk5' - } - - dependencies { - codeGeneration (libraries['maven.com_google_auto_value_auto_value'], - libraries['maven.com_google_code_findbugs_jsr305']) - - // Separate configuration (class path) for Linkage Checker - linkageChecker "com.google.cloud.tools:dependencies:1.5.12" - } - - compileJava.classpath += configurations.codeGeneration +def normalReleasableProjects = subprojects.findAll { + !nonReleaseProjects.contains(it.name) && !noDefaultPublications.contains(it.name) +} +configure(normalReleasableProjects) { + apply plugin: 'maven-publish' + apply plugin: 'signing' - eclipse { - jdt.file.withProperties { - it['org.eclipse.jdt.core.compiler.processAnnotations'] = 'enabled' - } - } + afterEvaluate { + publishing { + publications { + mavenJava(MavenPublication) { + version = project.version - tasks.eclipseJdt { - doFirst { - def aptPrefs = - file("${eclipseSettingsDir}/org.eclipse.jdt.apt.core.prefs") - aptPrefs.parentFile.mkdirs() - - aptPrefs.text = """\ - eclipse.preferences.version=1 - org.eclipse.jdt.apt.aptEnabled=true - org.eclipse.jdt.apt.genSrcDir=${eclipseAptFolder} - org.eclipse.jdt.apt.reconcileEnabled=true - """.stripIndent() - - file('.factorypath').withWriter { - new groovy.xml.MarkupBuilder(it).'factorypath' { - project.configurations.codeGeneration.each { dep-> - factorypathentry( - kind:'EXTJAR', - id:dep.absolutePath, - enabled:true, - runInBatchMode:false) - } - } - } - } - } + from components.java - tasks.cleanEclipseJdt { - doFirst { - delete file("${eclipseSettingsDir}/org.eclipse.jdt.apt.core.prefs"), - file('.factorypath') - } - } + artifact javadocJar + artifact sourcesJar + artifact testlibJar - // Publishing - // ---------- + pom { + name = 'GAX (Google Api eXtensions) for Java' + packaging = 'jar' + artifactId = project.name + description = 'Google Api eXtensions for Java' + url = 'https://github.com/googleapis/gax-java' - afterEvaluate { - if (!noDefaultPublications.contains(project.name)) { - publishing { - publications { - mavenJava(MavenPublication) { - version = project.version - - from components.java - - artifact javadocJar - artifact sourcesJar - artifact testlibJar - - pom { - name = 'GAX (Google Api eXtensions) for Java' - packaging = 'jar' - artifactId = project.name - description = 'Google Api eXtensions for Java' + scm { url = 'https://github.com/googleapis/gax-java' + connection = 'scm:git:https://github.com/googleapis/gax-java.git' + } - scm { - url = 'https://github.com/googleapis/gax-java' - connection = 'scm:git:https://github.com/googleapis/gax-java.git' - } - - licenses { - license { - name = 'BSD' - url = 'https://github.com/googleapis/gax-java/blob/master/LICENSE' - } + licenses { + license { + name = 'BSD' + url = 'https://github.com/googleapis/gax-java/blob/master/LICENSE' } + } - developers { - developer { - id = 'GoogleAPIs' - name = 'GoogleAPIs' - email = 'googleapis@googlegroups.com' - url = 'https://github.com/googleapis/gax-java' - organization = 'Google LLC' - organizationUrl = 'https://www.google.com' - } + developers { + developer { + id = 'GoogleAPIs' + name = 'GoogleAPIs' + email = 'googleapis@googlegroups.com' + url = 'https://github.com/googleapis/gax-java' + organization = 'Google LLC' + organizationUrl = 'https://www.google.com' } } } } - repositories { - maven { - url 'https://google.oss.sonatype.org/service/local/staging/deploy/maven2/' - credentials { - username = project.findProperty('ossrhUsername') - password = project.findProperty('ossrhPassword') - } + } + repositories { + maven { + url 'https://google.oss.sonatype.org/service/local/staging/deploy/maven2/' + credentials { + username = findProperty('ossrhUsername') + password = findProperty('ossrhPassword') } } } + } - task checkJavaLinkage(type: JavaExec) { - // Example invocation: - // ./gradlew gax-httpjson:checkJavaLinkage - dependsOn project.getTasksByName('publishMavenJavaPublicationToMavenLocal', true) - classpath = configurations.linkageChecker - main = 'com.google.cloud.tools.opensource.classpath.LinkageCheckerMain' - - def arguments = ['-a', "com.google.api:${project.name}:${project.version}"] - if (project.name == 'gax-grpc') { - // The exclusion file can be regenerated by '-o' option. See its Wiki for details: - // https://github.com/GoogleCloudPlatform/cloud-opensource-java/wiki/LinkageCheckerMain#exclusion-files - arguments += ['--exclusion-file', 'linkage-checker-exclusion.xml'] - } - args arguments + task checkJavaLinkage(type: JavaExec) { + // Example invocation: + // ./gradlew gax-httpjson:checkJavaLinkage + dependsOn project.getTasksByName('publishMavenJavaPublicationToMavenLocal', true) + classpath = configurations.linkageChecker + main = 'com.google.cloud.tools.opensource.classpath.LinkageCheckerMain' + + def arguments = ['-a', "com.google.api:${project.name}:${project.version}"] + if (project.name == 'gax-grpc') { + // The exclusion file can be regenerated by '-o' option. See its Wiki for details: + // https://github.com/GoogleCloudPlatform/cloud-opensource-java/wiki/LinkageCheckerMain#exclusion-files + arguments += ['--exclusion-file', 'linkage-checker-exclusion.xml'] } + args arguments } + } - signing { - if (!project.hasProperty('skip.signing') && !noDefaultPublications.contains(project.name)) { - if (project.hasProperty('signing.gnupg.executable')) { - useGpgCmd() - } - sign publishing.publications.mavenJava - } + signing { + required { gradle.taskGraph.hasTask ":${name}:publishToSonatype" } + if (project.hasProperty('signing.gnupg.executable')) { + useGpgCmd() } + sign publishing.publications } } @@ -378,7 +315,7 @@ javadoc.options { task javadocCombined(type: Javadoc) { source subprojects.collect {project -> project.sourceSets.main.allJava } classpath = files(subprojects.collect {project -> project.sourceSets.main.compileClasspath}) - destinationDir = new File(projectDir, 'tmp_docs') + destinationDir = file('tmp_docs') } // JavaDocV3 docFX @@ -386,12 +323,15 @@ task javadocCombined(type: Javadoc) { task javadocCombinedV3(type: Javadoc) { source subprojects.collect {project -> project.sourceSets.main.allJava } classpath = files(subprojects.collect {project -> project.sourceSets.main.compileClasspath}) - destinationDir = new File(projectDir, 'tmp_docs/docfx-yml') + destinationDir = file('tmp_docs/docfx-yml') options.addStringOption('encoding', 'UTF-8') - options.addStringOption("doclet", "com.microsoft.doclet.DocFxDoclet") - options.addStringOption("projectname", "gax") - options.docletpath = [file(System.getenv('KOKORO_GFILE_DIR') + "/java-docfx-doclet-1.3.0.jar")] + options.addStringOption('doclet', 'com.microsoft.doclet.DocFxDoclet') + options.addStringOption('projectname', 'gax') + options.docletpath = [file(System.getenv('KOKORO_GFILE_DIR') + '/java-docfx-doclet-1.3.0.jar')] + // Newer Gradle 6 passes -notimestamp by default, which the doclet above doesn't understand: + // https://github.com/gradle/gradle/issues/11898 + options.noTimestamp false } clean { @@ -483,7 +423,7 @@ task stageRelease { // 3. Remove tmp_gh-pages // Note: This task assumes that the 'stage_release' task has been completed. task finalizeRelease { - dependsOn 'publishDocs' + dependsOn publishDocs doLast { exec { commandLine 'rm', '-r', 'tmp_gh-pages' @@ -496,9 +436,9 @@ task finalizeRelease { // https://github.com/GoogleCloudPlatform/cloud-opensource-java/wiki/Linkage-Monitor#linkage-monitor-artifactstxt task createLinkageMonitorArtifactList { doLast { - def httpJsonVersion = project(":gax-httpjson").version + def httpJsonVersion = project(':gax-httpjson').version - new File(projectDir, "linkage-monitor-artifacts.txt").text = """ + new File('linkage-monitor-artifacts.txt').text = """ com.google.api:gax:$version com.google.api:gax-grpc:$version com.google.api:gax-httpjson:$httpJsonVersion diff --git a/dependencies.properties b/dependencies.properties index b6a0e73f8..10e4b6086 100644 --- a/dependencies.properties +++ b/dependencies.properties @@ -8,16 +8,16 @@ # Versions of oneself # {x-version-update-start:gax:current} -version.gax=2.6.0 +version.gax=2.7.0 # {x-version-update-end} # {x-version-update-start:gax:current} -version.gax_grpc=2.6.0 +version.gax_grpc=2.7.0 # {x-version-update-end} # {x-version-update-start:gax:current} -version.gax_bom=2.6.0 +version.gax_bom=2.7.0 # {x-version-update-end} # {x-version-update-start:gax-httpjson:current} -version.gax_httpjson=0.91.0 +version.gax_httpjson=0.92.0 # {x-version-update-end} # Versions for dependencies which actual artifacts differ between Bazel and Gradle. @@ -34,8 +34,8 @@ version.io_grpc=1.41.0 # 2) Replace all characters which are neither alphabetic nor digits with the underscore ('_') character maven.com_google_api_grpc_proto_google_common_protos=com.google.api.grpc:proto-google-common-protos:2.4.1 maven.com_google_api_grpc_grpc_google_common_protos=com.google.api.grpc:grpc-google-common-protos:2.4.1 -maven.com_google_auth_google_auth_library_oauth2_http=com.google.auth:google-auth-library-oauth2-http:0.27.0 -maven.com_google_auth_google_auth_library_credentials=com.google.auth:google-auth-library-credentials:1.0.0 +maven.com_google_auth_google_auth_library_oauth2_http=com.google.auth:google-auth-library-oauth2-http:1.2.1 +maven.com_google_auth_google_auth_library_credentials=com.google.auth:google-auth-library-credentials:1.2.1 maven.io_opencensus_opencensus_api=io.opencensus:opencensus-api:0.28.0 maven.io_opencensus_opencensus_contrib_grpc_metrics=io.opencensus:opencensus-contrib-grpc-metrics:0.28.0 maven.io_opencensus_opencensus_contrib_http_util=io.opencensus:opencensus-contrib-http-util:0.28.0 diff --git a/gax-bom/build.gradle b/gax-bom/build.gradle index e9718186c..272a09121 100644 --- a/gax-bom/build.gradle +++ b/gax-bom/build.gradle @@ -1,12 +1,15 @@ +plugins { + id 'maven-publish' + id 'signing' +} + archivesBaseName = 'gax-bom' -project.version = "2.6.0" // {x-version-update:gax-bom:current} +project.version = "2.7.0" // {x-version-update:gax-bom:current} -ext { - mavenJavaDir = "$buildDir/publications/mavenJava" - mavenJavaBomOutputFile = file(mavenJavaDir + "/pom-default.xml") - mavenJavaBomAscOutputFile = file(mavenJavaDir + "/pom-default.xml.asc") -} +def mavenJavaDir = "$buildDir/publications/mavenJava" +def mavenJavaBomOutputFile = file(mavenJavaDir + '/pom-default.xml') +def mavenJavaBomAscOutputFile = file(mavenJavaDir + '/pom-default.xml.asc') // Copy our pom.xml to the location where a generated POM would go task copyPom() { @@ -20,8 +23,6 @@ task copyPom() { } } -assemble.dependsOn copyPom - // We want to use our own pom.xml instead of the generated one, so we disable // the pom.xml generation and have the publish tasks depend on `copyPom` instead. tasks.whenTaskAdded { task -> @@ -36,66 +37,45 @@ tasks.whenTaskAdded { task -> } } -jar.enabled = false - -// Remove the default jar archive which is added by the 'java' plugin. -// We could avoid this by not applying the 'java' plugin to all submodules of -// gax, but that would create a little bit of a mess, so we hack around it here. -configurations.archives.artifacts.with { archives -> - def artifacts = [] - archives.each { - if (it.file =~ 'jar') { - // We can't just call `archives.remove(it)` here because it triggers - // a `ConcurrentModificationException`, so we add matching artifacts - // to another list, then remove those elements outside of this iteration. - artifacts.add(it) +// We can't use the `publishing` section from the main build.gradle because +// we don't want all the Java artifacts, and we want to use our own pom.xml +// instead of the generated one. +publishing { + publications { + mavenJava(MavenPublication) { + version = project.version + artifact mavenJavaBomOutputFile } } - artifacts.each { - archives.remove(it) + repositories { + maven { + url 'https://google.oss.sonatype.org/service/local/staging/deploy/maven2/' + credentials { + username = findProperty('ossrhUsername') + password = findProperty('ossrhPassword') + } + } } } -artifacts { - archives(mavenJavaBomOutputFile) { - builtBy copyPom +signing { + required { gradle.taskGraph.hasTask ":${name}:publishToSonatype" } + if (project.hasProperty('signing.gnupg.executable')) { + useGpgCmd() } + sign publishing.publications } -afterEvaluate { - // We can't use the `publishing` section from the main build.gradle because - // we don't want all the Java artifacts, and we want to use our own pom.xml - // instead of the generated one. - publishing { - publications { - mavenJava(MavenPublication) { - version = project.version - artifact mavenJavaBomOutputFile - } - } - repositories { - maven { - url 'https://google.oss.sonatype.org/service/local/staging/deploy/maven2/' - credentials { - username = project.findProperty('ossrhUsername') - password = project.findProperty('ossrhPassword') - } - } - } - } - - signing { - if (!project.hasProperty('skip.signing')) { - if (project.hasProperty('signing.gnupg.executable')) { - useGpgCmd() - } - sign publishing.publications.mavenJava - - publishing.publications.mavenJava(MavenPublication) { - artifact(mavenJavaBomAscOutputFile) { - extension 'pom.asc' - } - } +// Unlike other regular subprojects, pom.asc (signature file) generated by +// signing is not automatically picked up. It may be because gax-bom uses a +// pre-written pom.xml instead of using an auto-generated one. +// https://discuss.gradle.org/t/how-to-publish-artifacts-signatures-asc-files-using-maven-publish-plugin/7422 +task addPomAscFileToPublication { + onlyIf { mavenJavaBomAscOutputFile.exists() } + doLast { + publishing.publications.mavenJava(MavenPublication) { + artifact(mavenJavaBomAscOutputFile) { extension 'pom.asc' } } } } +signMavenJavaPublication.finalizedBy addPomAscFileToPublication diff --git a/gax-bom/pom.xml b/gax-bom/pom.xml index 07553f536..d83a4fcfc 100644 --- a/gax-bom/pom.xml +++ b/gax-bom/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.google.api gax-bom - 2.6.0 + 2.7.0 pom GAX (Google Api eXtensions) for Java Google Api eXtensions for Java @@ -33,34 +33,34 @@ com.google.api gax - 2.6.0 + 2.7.0 com.google.api gax - 2.6.0 + 2.7.0 testlib com.google.api gax-grpc - 2.6.0 + 2.7.0 com.google.api gax-grpc - 2.6.0 + 2.7.0 testlib com.google.api gax-httpjson - 0.91.0 + 0.92.0 com.google.api gax-httpjson - 0.91.0 + 0.92.0 testlib diff --git a/gax-grpc/build.gradle b/gax-grpc/build.gradle index cda65e20f..faa7912b6 100644 --- a/gax-grpc/build.gradle +++ b/gax-grpc/build.gradle @@ -1,22 +1,26 @@ -archivesBaseName = "gax-grpc" +archivesBaseName = 'gax-grpc' // TODO: Populate this from dependencies.properties version property (for proper Gradle-Bazel sync) -project.version = "2.6.0" // {x-version-update:gax-grpc:current} +project.version = "2.7.0" // {x-version-update:gax-grpc:current} dependencies { - implementation( project(':gax'), - libraries['maven.io_grpc_grpc_stub'], - libraries['maven.io_grpc_grpc_auth'], - libraries['maven.io_grpc_grpc_protobuf'], + api(project(':gax'), + libraries['maven.com_google_api_api_common'], + libraries['maven.com_google_api_grpc_proto_google_common_protos'], + libraries['maven.com_google_auth_google_auth_library_credentials'], libraries['maven.com_google_guava_guava'], + libraries['maven.io_grpc_grpc_api'], + libraries['maven.org_threeten_threetenbp']) + + implementation(libraries['maven.com_google_auth_google_auth_library_oauth2_http'], libraries['maven.com_google_code_findbugs_jsr305'], - libraries['maven.org_threeten_threetenbp'], - libraries['maven.com_google_auth_google_auth_library_oauth2_http'], - libraries['maven.com_google_auth_google_auth_library_credentials'], - libraries['maven.com_google_api_grpc_proto_google_common_protos'], - libraries['maven.com_google_api_api_common'], + libraries['maven.io_grpc_grpc_alts'], + libraries['maven.io_grpc_grpc_auth'], libraries['maven.io_grpc_grpc_netty_shaded'], - libraries['maven.io_grpc_grpc_alts']) + libraries['maven.io_grpc_grpc_protobuf'], + libraries['maven.io_grpc_grpc_stub']) + + runtimeOnly libraries['maven.io_grpc_grpc_xds'] compileOnly libraries['maven.com_google_auto_value_auto_value'] diff --git a/gax-grpc/src/main/java/com/google/api/gax/grpc/GrpcMetadataHandlerInterceptor.java b/gax-grpc/src/main/java/com/google/api/gax/grpc/GrpcMetadataHandlerInterceptor.java index 1edf2eb5b..e405336c2 100644 --- a/gax-grpc/src/main/java/com/google/api/gax/grpc/GrpcMetadataHandlerInterceptor.java +++ b/gax-grpc/src/main/java/com/google/api/gax/grpc/GrpcMetadataHandlerInterceptor.java @@ -73,8 +73,8 @@ public void onHeaders(Metadata headers) { @Override public void onClose(Status status, Metadata trailers) { - super.onClose(status, trailers); metadataHandler.onTrailers(trailers); + super.onClose(status, trailers); } }; super.start(forwardingResponseListener, headers); diff --git a/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java b/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java index 225d76d6d..d441a0c9a 100644 --- a/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java +++ b/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java @@ -83,6 +83,7 @@ public final class InstantiatingGrpcChannelProvider implements TransportChannelP static final String DIRECT_PATH_ENV_VAR = "GOOGLE_CLOUD_ENABLE_DIRECT_PATH"; private static final String DIRECT_PATH_ENV_DISABLE_DIRECT_PATH = "GOOGLE_CLOUD_DISABLE_DIRECT_PATH"; + private static final String DIRECT_PATH_ENV_ENABLE_XDS = "GOOGLE_CLOUD_ENABLE_DIRECT_PATH_XDS"; static final long DIRECT_PATH_KEEP_ALIVE_TIME_SECONDS = 3600; static final long DIRECT_PATH_KEEP_ALIVE_TIMEOUT_SECONDS = 20; // reduce the thundering herd problem of too many channels trying to (re)connect at the same time @@ -330,16 +331,23 @@ private ManagedChannel createSingleChannel() throws IOException, GeneralSecurity ManagedChannelBuilder builder; - // TODO(weiranf): Add API in ComputeEngineCredentials to check default service account. + // Check DirectPath traffic. + boolean isDirectPathXdsEnabled = false; if (isDirectPathEnabled(serviceAddress) && isNonDefaultServiceAccountAllowed() && isOnComputeEngine()) { - builder = ComputeEngineChannelBuilder.forAddress(serviceAddress, port); + isDirectPathXdsEnabled = Boolean.parseBoolean(envProvider.getenv(DIRECT_PATH_ENV_ENABLE_XDS)); + if (isDirectPathXdsEnabled) { + // google-c2p resolver target must not have a port number + builder = ComputeEngineChannelBuilder.forTarget("google-c2p:///" + serviceAddress); + } else { + builder = ComputeEngineChannelBuilder.forAddress(serviceAddress, port); + builder.defaultServiceConfig(directPathServiceConfig); + } // Set default keepAliveTime and keepAliveTimeout when directpath environment is enabled. // Will be overridden by user defined values if any. builder.keepAliveTime(DIRECT_PATH_KEEP_ALIVE_TIME_SECONDS, TimeUnit.SECONDS); builder.keepAliveTimeout(DIRECT_PATH_KEEP_ALIVE_TIMEOUT_SECONDS, TimeUnit.SECONDS); - builder.defaultServiceConfig(directPathServiceConfig); } else { ChannelCredentials channelCredentials = createMtlsChannelCredentials(); if (channelCredentials != null) { @@ -348,10 +356,13 @@ && isOnComputeEngine()) { builder = ManagedChannelBuilder.forAddress(serviceAddress, port); } } + // google-c2p resolver requires service config lookup + if (!isDirectPathXdsEnabled) { + // See https://github.com/googleapis/gapic-generator/issues/2816 + builder.disableServiceConfigLookUp(); + } builder = builder - // See https://github.com/googleapis/gapic-generator/issues/2816 - .disableServiceConfigLookUp() .intercept(new GrpcChannelUUIDInterceptor()) .intercept(headerInterceptor) .intercept(metadataHandlerInterceptor) diff --git a/gax-grpc/src/test/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProviderTest.java b/gax-grpc/src/test/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProviderTest.java index 72f3cc464..ed01d241e 100644 --- a/gax-grpc/src/test/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProviderTest.java +++ b/gax-grpc/src/test/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProviderTest.java @@ -67,6 +67,7 @@ @RunWith(JUnit4.class) public class InstantiatingGrpcChannelProviderTest extends AbstractMtlsTransportChannelTest { + @Test public void testEndpoint() { String endpoint = "localhost:8080"; @@ -164,11 +165,8 @@ public void testToBuilder() { Duration keepaliveTime = Duration.ofSeconds(1); Duration keepaliveTimeout = Duration.ofSeconds(2); ApiFunction channelConfigurator = - new ApiFunction() { - @Override - public ManagedChannelBuilder apply(ManagedChannelBuilder input) { - throw new UnsupportedOperationException(); - } + builder -> { + throw new UnsupportedOperationException(); }; Map directPathServiceConfig = ImmutableMap.of("loadbalancingConfig", "grpclb"); @@ -266,15 +264,13 @@ public void testWithGCECredentials() throws IOException { executor.shutdown(); ApiFunction channelConfigurator = - new ApiFunction() { - public ManagedChannelBuilder apply(ManagedChannelBuilder channelBuilder) { - if (InstantiatingGrpcChannelProvider.isOnComputeEngine()) { - assertThat(channelBuilder instanceof ComputeEngineChannelBuilder).isTrue(); - } else { - assertThat(channelBuilder instanceof ComputeEngineChannelBuilder).isFalse(); - } - return channelBuilder; + channelBuilder -> { + if (InstantiatingGrpcChannelProvider.isOnComputeEngine()) { + assertThat(channelBuilder).isInstanceOf(ComputeEngineChannelBuilder.class); + } else { + assertThat(channelBuilder).isNotInstanceOf(ComputeEngineChannelBuilder.class); } + return channelBuilder; }; TransportChannelProvider provider = @@ -303,12 +299,10 @@ public void testWithNonGCECredentials() throws IOException { executor.shutdown(); ApiFunction channelConfigurator = - new ApiFunction() { - public ManagedChannelBuilder apply(ManagedChannelBuilder channelBuilder) { - // Clients with non-GCE credentials will not attempt DirectPath. - assertThat(channelBuilder instanceof ComputeEngineChannelBuilder).isFalse(); - return channelBuilder; - } + channelBuilder -> { + // Clients with non-GCE credentials will not attempt DirectPath. + assertThat(channelBuilder instanceof ComputeEngineChannelBuilder).isFalse(); + return channelBuilder; }; TransportChannelProvider provider = @@ -334,6 +328,7 @@ public void testWithDirectPathDisabled() throws IOException { ApiFunction channelConfigurator = new ApiFunction() { + @Override public ManagedChannelBuilder apply(ManagedChannelBuilder channelBuilder) { // Clients without setting attemptDirectPath flag will not attempt DirectPath assertThat(channelBuilder instanceof ComputeEngineChannelBuilder).isFalse(); @@ -363,12 +358,10 @@ public void testWithNoDirectPathFlagSet() throws IOException { executor.shutdown(); ApiFunction channelConfigurator = - new ApiFunction() { - public ManagedChannelBuilder apply(ManagedChannelBuilder channelBuilder) { - // Clients without setting attemptDirectPath flag will not attempt DirectPath - assertThat(channelBuilder instanceof ComputeEngineChannelBuilder).isFalse(); - return channelBuilder; - } + channelBuilder -> { + // Clients without setting attemptDirectPath flag will not attempt DirectPath + assertThat(channelBuilder instanceof ComputeEngineChannelBuilder).isFalse(); + return channelBuilder; }; TransportChannelProvider provider = diff --git a/gax-httpjson/build.gradle b/gax-httpjson/build.gradle index fae4a95b1..863f3bd65 100644 --- a/gax-httpjson/build.gradle +++ b/gax-httpjson/build.gradle @@ -1,26 +1,27 @@ -archivesBaseName = "gax-httpjson" +archivesBaseName = 'gax-httpjson' // TODO: Populate this from dependencies.properties version property (for proper Gradle-Bazel sync) -project.version = "0.91.0" // {x-version-update:gax-httpjson:current} +project.version = "0.92.0" // {x-version-update:gax-httpjson:current} dependencies { - implementation( project(':gax'), - libraries['maven.com_google_protobuf'], - libraries['maven.com_google_protobuf_java_util'], + api(project(':gax'), + libraries['maven.com_google_api_api_common'], + libraries['maven.com_google_api_grpc_proto_google_common_protos'], + libraries['maven.com_google_auth_google_auth_library_credentials'], libraries['maven.com_google_code_gson_gson'], libraries['maven.com_google_guava_guava'], - libraries['maven.com_google_code_findbugs_jsr305'], - libraries['maven.org_threeten_threetenbp'], libraries['maven.com_google_http_client_google_http_client'], + libraries['maven.com_google_protobuf'], + libraries['maven.org_threeten_threetenbp']) + + implementation(libraries['maven.com_google_auth_google_auth_library_oauth2_http'], + libraries['maven.com_google_code_findbugs_jsr305'], libraries['maven.com_google_http_client_google_http_client_gson'], - libraries['maven.com_google_auth_google_auth_library_oauth2_http'], - libraries['maven.com_google_auth_google_auth_library_credentials'], - libraries['maven.com_google_api_grpc_proto_google_common_protos'], - libraries['maven.com_google_api_api_common']) + libraries['maven.com_google_protobuf_java_util']) compileOnly libraries['maven.com_google_auto_value_auto_value'] - testImplementation( project(':gax').sourceSets.test.output, + testImplementation(project(':gax').sourceSets.test.output, libraries['maven.junit_junit'], libraries['maven.org_mockito_mockito_core'], libraries['maven.com_google_truth_truth']) diff --git a/gax/build.gradle b/gax/build.gradle index 14b708573..ae94e1a05 100644 --- a/gax/build.gradle +++ b/gax/build.gradle @@ -1,22 +1,24 @@ archivesBaseName = "gax" // TODO: Populate this from dependencies.properties version property (for proper Gradle-Bazel sync) -project.version = "2.6.0" // {x-version-update:gax:current} +project.version = "2.7.0" // {x-version-update:gax:current} dependencies { - implementation (libraries['maven.com_google_guava_guava'], + api(libraries['maven.com_google_api_api_common'], + libraries['maven.com_google_auth_google_auth_library_credentials'], + libraries['maven.org_threeten_threetenbp']) + + implementation(libraries['maven.com_google_auth_google_auth_library_oauth2_http'], libraries['maven.com_google_code_findbugs_jsr305'], - libraries['maven.org_threeten_threetenbp'], - libraries['maven.com_google_auth_google_auth_library_oauth2_http'], - libraries['maven.com_google_api_api_common'], + libraries['maven.com_google_guava_guava'], libraries['maven.io_opencensus_opencensus_api']) compileOnly libraries['maven.com_google_auto_value_auto_value'] - testImplementation( libraries['maven.junit_junit'], + testImplementation(libraries['maven.junit_junit'], libraries['maven.org_mockito_mockito_core'], libraries['maven.com_google_truth_truth'], - libraries['maven.com_google_auto_value_auto_value'] ) + libraries['maven.com_google_auto_value_auto_value']) annotationProcessor libraries['maven.com_google_auto_value_auto_value'] testAnnotationProcessor libraries['maven.com_google_auto_value_auto_value'] diff --git a/gax/src/main/java/com/google/api/gax/batching/Batcher.java b/gax/src/main/java/com/google/api/gax/batching/Batcher.java index d01f79f4a..8ac78ef2f 100644 --- a/gax/src/main/java/com/google/api/gax/batching/Batcher.java +++ b/gax/src/main/java/com/google/api/gax/batching/Batcher.java @@ -32,6 +32,7 @@ import com.google.api.core.ApiFuture; import com.google.api.core.BetaApi; import com.google.api.core.InternalExtensionOnly; +import com.google.api.gax.rpc.ApiCallContext; /** * Represents a batching context where individual elements will be accumulated and flushed in a @@ -49,6 +50,9 @@ @InternalExtensionOnly public interface Batcher extends AutoCloseable { + /** {@link ApiCallContext.Key} for tracking batch total throttled time */ + ApiCallContext.Key THROTTLED_TIME_KEY = ApiCallContext.Key.create("total_throttled_time"); + /** * Queues the passed in element to be sent at some point in the future. * diff --git a/gax/src/main/java/com/google/api/gax/batching/BatcherImpl.java b/gax/src/main/java/com/google/api/gax/batching/BatcherImpl.java index aeeab82b2..743d25c57 100644 --- a/gax/src/main/java/com/google/api/gax/batching/BatcherImpl.java +++ b/gax/src/main/java/com/google/api/gax/batching/BatcherImpl.java @@ -40,9 +40,11 @@ import com.google.api.gax.batching.FlowController.FlowControlException; import com.google.api.gax.batching.FlowController.FlowControlRuntimeException; import com.google.api.gax.batching.FlowController.LimitExceededBehavior; +import com.google.api.gax.rpc.ApiCallContext; import com.google.api.gax.rpc.UnaryCallable; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; +import com.google.common.base.Stopwatch; import com.google.common.util.concurrent.Futures; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; @@ -93,6 +95,7 @@ public class BatcherImpl private SettableApiFuture closeFuture; private final BatcherStats batcherStats = new BatcherStats(); private final FlowController flowController; + private final ApiCallContext callContext; /** * @param batchingDescriptor a {@link BatchingDescriptor} for transforming individual elements @@ -100,7 +103,10 @@ public class BatcherImpl * @param unaryCallable a {@link UnaryCallable} object * @param prototype a {@link RequestT} object * @param batchingSettings a {@link BatchingSettings} with configuration of thresholds + * @deprecated Please instantiate the Batcher with {@link FlowController} and {@link + * ApiCallContext} */ + @Deprecated public BatcherImpl( BatchingDescriptor batchingDescriptor, UnaryCallable unaryCallable, @@ -108,7 +114,7 @@ public BatcherImpl( BatchingSettings batchingSettings, ScheduledExecutorService executor) { - this(batchingDescriptor, unaryCallable, prototype, batchingSettings, executor, null); + this(batchingDescriptor, unaryCallable, prototype, batchingSettings, executor, null, null); } /** @@ -119,7 +125,9 @@ public BatcherImpl( * @param batchingSettings a {@link BatchingSettings} with configuration of thresholds * @param flowController a {@link FlowController} for throttling requests. If it's null, create a * {@link FlowController} object from {@link BatchingSettings#getFlowControlSettings()}. + * @deprecated Please instantiate the Batcher with {@link ApiCallContext} */ + @Deprecated public BatcherImpl( BatchingDescriptor batchingDescriptor, UnaryCallable unaryCallable, @@ -128,6 +136,35 @@ public BatcherImpl( ScheduledExecutorService executor, @Nullable FlowController flowController) { + this( + batchingDescriptor, + unaryCallable, + prototype, + batchingSettings, + executor, + flowController, + null); + } + + /** + * @param batchingDescriptor a {@link BatchingDescriptor} for transforming individual elements + * into wrappers request and response + * @param unaryCallable a {@link UnaryCallable} object + * @param prototype a {@link RequestT} object + * @param batchingSettings a {@link BatchingSettings} with configuration of thresholds + * @param flowController a {@link FlowController} for throttling requests. If it's null, create a + * {@link FlowController} object from {@link BatchingSettings#getFlowControlSettings()}. + * @param callContext a {@link ApiCallContext} object that'll be merged in unaryCallable + */ + public BatcherImpl( + BatchingDescriptor batchingDescriptor, + UnaryCallable unaryCallable, + RequestT prototype, + BatchingSettings batchingSettings, + ScheduledExecutorService executor, + @Nullable FlowController flowController, + @Nullable ApiCallContext callContext) { + this.batchingDescriptor = Preconditions.checkNotNull(batchingDescriptor, "batching descriptor cannot be null"); this.unaryCallable = Preconditions.checkNotNull(unaryCallable, "callable cannot be null"); @@ -168,6 +205,7 @@ public BatcherImpl( scheduledFuture = Futures.immediateCancelledFuture(); } currentBatcherReference = new BatcherReference(this); + this.callContext = callContext; } /** {@inheritDoc} */ @@ -192,16 +230,18 @@ public ApiFuture add(ElementT element) { // class, which made it seem unnecessary to have blocking and non-blocking semaphore // implementations. Some refactoring may be needed for the optimized implementation. So we'll // defer it till we decide on if refactoring FlowController is necessary. + Stopwatch stopwatch = Stopwatch.createStarted(); try { flowController.reserve(1, batchingDescriptor.countBytes(element)); } catch (FlowControlException e) { // This exception will only be thrown if the FlowController is set to ThrowException behavior throw FlowControlRuntimeException.fromFlowControlException(e); } + long throttledTimeMs = stopwatch.elapsed(TimeUnit.MILLISECONDS); SettableApiFuture result = SettableApiFuture.create(); synchronized (elementLock) { - currentOpenBatch.add(element, result); + currentOpenBatch.add(element, result, throttledTimeMs); } if (currentOpenBatch.hasAnyThresholdReached()) { @@ -230,8 +270,14 @@ public void sendOutstanding() { currentOpenBatch = new Batch<>(prototype, batchingDescriptor, batchingSettings, batcherStats); } + // This check is for old clients that instantiated the batcher without ApiCallContext + ApiCallContext callContextWithOption = null; + if (callContext != null) { + callContextWithOption = + callContext.withOption(THROTTLED_TIME_KEY, accumulatedBatch.totalThrottledTimeMs); + } final ApiFuture batchResponse = - unaryCallable.futureCall(accumulatedBatch.builder.build()); + unaryCallable.futureCall(accumulatedBatch.builder.build(), callContextWithOption); numOfOutstandingBatches.incrementAndGet(); ApiFutures.addCallback( @@ -367,6 +413,7 @@ private static class Batch { private long elementCounter = 0; private long byteCounter = 0; + private long totalThrottledTimeMs = 0; private Batch( RequestT prototype, @@ -383,11 +430,12 @@ private Batch( this.batcherStats = batcherStats; } - void add(ElementT element, SettableApiFuture result) { + void add(ElementT element, SettableApiFuture result, long throttledTimeMs) { builder.add(element); entries.add(BatchEntry.create(element, result)); elementCounter++; byteCounter += descriptor.countBytes(element); + totalThrottledTimeMs += throttledTimeMs; } void onBatchSuccess(ResponseT response) { diff --git a/gax/src/main/java/com/google/api/gax/rpc/AttemptCallable.java b/gax/src/main/java/com/google/api/gax/rpc/AttemptCallable.java index e053d5583..6b419f1d4 100644 --- a/gax/src/main/java/com/google/api/gax/rpc/AttemptCallable.java +++ b/gax/src/main/java/com/google/api/gax/rpc/AttemptCallable.java @@ -82,7 +82,7 @@ public ResponseT call() { callContext .getTracer() - .attemptStarted(externalFuture.getAttemptSettings().getOverallAttemptCount()); + .attemptStarted(request, externalFuture.getAttemptSettings().getOverallAttemptCount()); ApiFuture internalFuture = callable.futureCall(request, callContext); externalFuture.setAttemptFuture(internalFuture); diff --git a/gax/src/main/java/com/google/api/gax/rpc/ServerStreamingAttemptCallable.java b/gax/src/main/java/com/google/api/gax/rpc/ServerStreamingAttemptCallable.java index cdae46ffc..0c71d1242 100644 --- a/gax/src/main/java/com/google/api/gax/rpc/ServerStreamingAttemptCallable.java +++ b/gax/src/main/java/com/google/api/gax/rpc/ServerStreamingAttemptCallable.java @@ -229,7 +229,7 @@ public Void call() { attemptContext .getTracer() - .attemptStarted(outerRetryingFuture.getAttemptSettings().getOverallAttemptCount()); + .attemptStarted(request, outerRetryingFuture.getAttemptSettings().getOverallAttemptCount()); innerCallable.call( request, diff --git a/gax/src/main/java/com/google/api/gax/rpc/StubSettings.java b/gax/src/main/java/com/google/api/gax/rpc/StubSettings.java index 825aa9d7a..04f1d59c9 100644 --- a/gax/src/main/java/com/google/api/gax/rpc/StubSettings.java +++ b/gax/src/main/java/com/google/api/gax/rpc/StubSettings.java @@ -176,6 +176,7 @@ public ApiTracerFactory getTracerFactory() { return tracerFactory; } + @Override public String toString() { return MoreObjects.toStringHelper(this) .add("backgroundExecutorProvider", backgroundExecutorProvider) @@ -535,6 +536,7 @@ protected static void applyToAllUnaryMethods( public abstract > StubSettings build() throws IOException; + @Override public String toString() { return MoreObjects.toStringHelper(this) .add("backgroundExecutorProvider", backgroundExecutorProvider) diff --git a/gax/src/main/java/com/google/api/gax/tracing/ApiTracer.java b/gax/src/main/java/com/google/api/gax/tracing/ApiTracer.java index bc329630e..3176be4b9 100644 --- a/gax/src/main/java/com/google/api/gax/tracing/ApiTracer.java +++ b/gax/src/main/java/com/google/api/gax/tracing/ApiTracer.java @@ -83,9 +83,21 @@ public interface ApiTracer { * start of the operation. The attemptNumber is zero based. So the initial attempt will be 0. * * @param attemptNumber the zero based sequential attempt number. + * @deprecated Please use {@link #attemptStarted(Object, int)} instead. */ + @Deprecated void attemptStarted(int attemptNumber); + /** + * Adds an annotation that an attempt is about to start with additional information from the + * request. In general this should occur at the very start of the operation. The attemptNumber is + * zero based. So the initial attempt will be 0. + * + * @param attemptNumber the zero based sequential attempt number. + * @param request request of this attempt. + */ + void attemptStarted(Object request, int attemptNumber); + /** Adds an annotation that the attempt succeeded. */ void attemptSucceeded(); diff --git a/gax/src/main/java/com/google/api/gax/tracing/BaseApiTracer.java b/gax/src/main/java/com/google/api/gax/tracing/BaseApiTracer.java index 4ff8e901f..538708b87 100644 --- a/gax/src/main/java/com/google/api/gax/tracing/BaseApiTracer.java +++ b/gax/src/main/java/com/google/api/gax/tracing/BaseApiTracer.java @@ -85,6 +85,11 @@ public void attemptStarted(int attemptNumber) { // noop } + @Override + public void attemptStarted(Object request, int attemptNumber) { + attemptStarted(attemptNumber); + } + @Override public void attemptSucceeded() { // noop diff --git a/gax/src/main/java/com/google/api/gax/tracing/OpencensusTracer.java b/gax/src/main/java/com/google/api/gax/tracing/OpencensusTracer.java index 8025917dc..ea4c5f903 100644 --- a/gax/src/main/java/com/google/api/gax/tracing/OpencensusTracer.java +++ b/gax/src/main/java/com/google/api/gax/tracing/OpencensusTracer.java @@ -307,6 +307,12 @@ public void attemptStarted(int attemptNumber) { // This simply is used for state management. } + /** {@inheritDoc} */ + @Override + public void attemptStarted(Object request, int attemptNumber) { + attemptStarted(attemptNumber); + } + /** {@inheritDoc} */ @Override public void attemptSucceeded() { diff --git a/gax/src/test/java/com/google/api/gax/batching/BatcherImplTest.java b/gax/src/test/java/com/google/api/gax/batching/BatcherImplTest.java index 10ccb1453..c3a1ce0bb 100644 --- a/gax/src/test/java/com/google/api/gax/batching/BatcherImplTest.java +++ b/gax/src/test/java/com/google/api/gax/batching/BatcherImplTest.java @@ -33,6 +33,7 @@ import static com.google.api.gax.rpc.testing.FakeBatchableApi.callLabeledIntSquarer; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; +import static org.mockito.Mockito.when; import com.google.api.core.ApiFuture; import com.google.api.core.ApiFutures; @@ -75,6 +76,8 @@ import org.junit.function.ThrowingRunnable; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; import org.threeten.bp.Duration; @RunWith(JUnit4.class) @@ -132,9 +135,10 @@ public void testSendOutstanding() { SQUARER_BATCHING_DESC_V2, new LabeledIntSquarerCallable() { @Override - public ApiFuture> futureCall(LabeledIntList request) { + public ApiFuture> futureCall( + LabeledIntList request, ApiCallContext context) { callableCounter.incrementAndGet(); - return super.futureCall(request); + return super.futureCall(request, context); } }, labeledIntList, @@ -838,8 +842,23 @@ public void testThrottlingBlocking() throws Exception { .setMaxOutstandingElementCount(1L) .build()); ExecutorService executor = Executors.newSingleThreadExecutor(); + + ApiCallContext callContext = Mockito.mock(ApiCallContext.class); + ArgumentCaptor> key = + ArgumentCaptor.forClass(ApiCallContext.Key.class); + ArgumentCaptor value = ArgumentCaptor.forClass(Long.class); + when(callContext.withOption(key.capture(), value.capture())).thenReturn(callContext); + long throttledTime = 10; + try (final Batcher batcher = - createDefaultBatcherImpl(settings, flowController)) { + new BatcherImpl<>( + SQUARER_BATCHING_DESC_V2, + callLabeledIntSquarer, + labeledIntList, + settings, + EXECUTOR, + flowController, + callContext)) { flowController.reserve(1, 1); Future future = executor.submit( @@ -851,6 +870,7 @@ public void run() { }); try { future.get(10, TimeUnit.MILLISECONDS); + Thread.sleep(throttledTime); assertWithMessage("adding elements to batcher should be blocked by FlowControlled").fail(); } catch (TimeoutException e) { // expected @@ -861,6 +881,9 @@ public void run() { } catch (TimeoutException e) { assertWithMessage("adding elements to batcher should not be blocked").fail(); } + // Verify that throttled time is recorded in ApiCallContext + assertThat(key.getValue()).isSameInstanceAs(Batcher.THROTTLED_TIME_KEY); + assertThat(value.getValue()).isAtLeast(throttledTime); } finally { executor.shutdownNow(); } diff --git a/gax/src/test/java/com/google/api/gax/retrying/AbstractRetryingExecutorTest.java b/gax/src/test/java/com/google/api/gax/retrying/AbstractRetryingExecutorTest.java index 3be825747..e376a7c7a 100644 --- a/gax/src/test/java/com/google/api/gax/retrying/AbstractRetryingExecutorTest.java +++ b/gax/src/test/java/com/google/api/gax/retrying/AbstractRetryingExecutorTest.java @@ -37,6 +37,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.times; @@ -115,7 +116,7 @@ private RetrySettings getDefaultRetrySettings() { @Test public void testSuccess() throws Exception { - FailingCallable callable = new FailingCallable(0, "SUCCESS", tracer); + FailingCallable callable = new FailingCallable(0, "request", "SUCCESS", tracer); RetryingExecutorWithContext executor = getExecutor(getAlgorithm(getDefaultRetrySettings(), 0, null)); RetryingFuture future = executor.createFuture(callable, retryingContext); @@ -124,14 +125,14 @@ public void testSuccess() throws Exception { assertFutureSuccess(future); assertEquals(0, future.getAttemptSettings().getAttemptCount()); - verify(tracer, times(1)).attemptStarted(0); + verify(tracer, times(1)).attemptStarted(eq("request"), eq(0)); verify(tracer, times(1)).attemptSucceeded(); verifyNoMoreInteractions(tracer); } @Test public void testSuccessWithFailures() throws Exception { - FailingCallable callable = new FailingCallable(5, "SUCCESS", tracer); + FailingCallable callable = new FailingCallable(5, "request", "SUCCESS", tracer); RetryingExecutorWithContext executor = getExecutor(getAlgorithm(getDefaultRetrySettings(), 0, null)); RetryingFuture future = executor.createFuture(callable, retryingContext); @@ -140,7 +141,7 @@ public void testSuccessWithFailures() throws Exception { assertFutureSuccess(future); assertEquals(5, future.getAttemptSettings().getAttemptCount()); - verify(tracer, times(6)).attemptStarted(anyInt()); + verify(tracer, times(6)).attemptStarted(eq("request"), anyInt()); verify(tracer, times(5)).attemptFailed(any(Throwable.class), any(Duration.class)); verify(tracer, times(1)).attemptSucceeded(); verifyNoMoreInteractions(tracer); @@ -148,7 +149,7 @@ public void testSuccessWithFailures() throws Exception { @Test public void testSuccessWithFailuresPeekGetAttempt() throws Exception { - FailingCallable callable = new FailingCallable(5, "SUCCESS", tracer); + FailingCallable callable = new FailingCallable(5, "request", "SUCCESS", tracer); RetryingExecutorWithContext executor = getExecutor(getAlgorithm(getDefaultRetrySettings(), 0, null)); RetryingFuture future = executor.createFuture(callable, retryingContext); @@ -174,7 +175,7 @@ public void testSuccessWithFailuresPeekGetAttempt() throws Exception { @Test public void testMaxRetriesExceeded() throws Exception { - FailingCallable callable = new FailingCallable(6, "FAILURE", tracer); + FailingCallable callable = new FailingCallable(6, "request", "FAILURE", tracer); RetryingExecutorWithContext executor = getExecutor(getAlgorithm(getDefaultRetrySettings(), 0, null)); RetryingFuture future = executor.createFuture(callable, retryingContext); @@ -183,7 +184,7 @@ public void testMaxRetriesExceeded() throws Exception { assertFutureFail(future, CustomException.class); assertEquals(5, future.getAttemptSettings().getAttemptCount()); - verify(tracer, times(6)).attemptStarted(anyInt()); + verify(tracer, times(6)).attemptStarted(eq("request"), anyInt()); verify(tracer, times(5)).attemptFailed(any(Throwable.class), any(Duration.class)); verify(tracer, times(1)).attemptFailedRetriesExhausted(any(Throwable.class)); verifyNoMoreInteractions(tracer); @@ -202,7 +203,7 @@ public void testTotalTimeoutExceeded() throws Exception { getExecutor( getAlgorithm( useContextRetrySettings ? getDefaultRetrySettings() : retrySettings, 0, null)); - FailingCallable callable = new FailingCallable(6, "FAILURE", tracer); + FailingCallable callable = new FailingCallable(6, "request", "FAILURE", tracer); RetryingContext context; if (useContextRetrySettings) { context = FakeCallContext.createDefault().withTracer(tracer).withRetrySettings(retrySettings); @@ -215,14 +216,14 @@ public void testTotalTimeoutExceeded() throws Exception { assertFutureFail(future, CustomException.class); assertTrue(future.getAttemptSettings().getAttemptCount() < 4); - verify(tracer, times(1)).attemptStarted(anyInt()); + verify(tracer, times(1)).attemptStarted(eq("request"), anyInt()); verify(tracer, times(1)).attemptFailedRetriesExhausted(any(Throwable.class)); verifyNoMoreInteractions(tracer); } @Test public void testCancelOuterFutureBeforeStart() throws Exception { - FailingCallable callable = new FailingCallable(4, "SUCCESS", tracer); + FailingCallable callable = new FailingCallable(4, "request", "SUCCESS", tracer); RetrySettings retrySettings = FAST_RETRY_SETTINGS @@ -248,7 +249,7 @@ public void testCancelOuterFutureBeforeStart() throws Exception { @Test public void testCancelByRetryingAlgorithm() throws Exception { - FailingCallable callable = new FailingCallable(6, "FAILURE", tracer); + FailingCallable callable = new FailingCallable(6, "request", "FAILURE", tracer); RetryingExecutorWithContext executor = getExecutor(getAlgorithm(getDefaultRetrySettings(), 5, new CancellationException())); RetryingFuture future = executor.createFuture(callable, retryingContext); @@ -257,7 +258,7 @@ public void testCancelByRetryingAlgorithm() throws Exception { assertFutureCancel(future); assertEquals(4, future.getAttemptSettings().getAttemptCount()); - verify(tracer, times(5)).attemptStarted(anyInt()); + verify(tracer, times(5)).attemptStarted(eq("request"), anyInt()); // Pre-apocalypse failures verify(tracer, times(4)).attemptFailed(any(Throwable.class), any(Duration.class)); // Apocalypse failure @@ -267,7 +268,7 @@ public void testCancelByRetryingAlgorithm() throws Exception { @Test public void testUnexpectedExceptionFromRetryAlgorithm() throws Exception { - FailingCallable callable = new FailingCallable(6, "FAILURE", tracer); + FailingCallable callable = new FailingCallable(6, "request", "FAILURE", tracer); RetryingExecutorWithContext executor = getExecutor(getAlgorithm(getDefaultRetrySettings(), 5, new RuntimeException())); RetryingFuture future = executor.createFuture(callable, retryingContext); @@ -276,7 +277,7 @@ public void testUnexpectedExceptionFromRetryAlgorithm() throws Exception { assertFutureFail(future, RuntimeException.class); assertEquals(4, future.getAttemptSettings().getAttemptCount()); - verify(tracer, times(5)).attemptStarted(anyInt()); + verify(tracer, times(5)).attemptStarted(eq("request"), anyInt()); // Pre-apocalypse failures verify(tracer, times(4)).attemptFailed(any(Throwable.class), any(Duration.class)); // Apocalypse failure @@ -302,7 +303,7 @@ public void testPollExceptionByPollAlgorithm() throws Exception { NanoClock.getDefaultClock())); RetryingExecutorWithContext executor = getExecutor(retryAlgorithm); - FailingCallable callable = new FailingCallable(6, "FAILURE", tracer); + FailingCallable callable = new FailingCallable(6, "request", "FAILURE", tracer); RetryingContext context; if (useContextRetrySettings) { context = FakeCallContext.createDefault().withTracer(tracer).withRetrySettings(retrySettings); @@ -315,7 +316,7 @@ public void testPollExceptionByPollAlgorithm() throws Exception { assertFutureFail(future, PollException.class); assertTrue(future.getAttemptSettings().getAttemptCount() < 4); - verify(tracer, times(1)).attemptStarted(anyInt()); + verify(tracer, times(1)).attemptStarted(eq("request"), anyInt()); verify(tracer, times(1)).attemptPermanentFailure(any(PollException.class)); verifyNoMoreInteractions(tracer); } diff --git a/gax/src/test/java/com/google/api/gax/retrying/FailingCallable.java b/gax/src/test/java/com/google/api/gax/retrying/FailingCallable.java index 07fa1c59d..9b7524ec6 100644 --- a/gax/src/test/java/com/google/api/gax/retrying/FailingCallable.java +++ b/gax/src/test/java/com/google/api/gax/retrying/FailingCallable.java @@ -62,10 +62,12 @@ class FailingCallable implements Callable { private AtomicInteger attemptsCount = new AtomicInteger(0); private final ApiTracer tracer; private final int expectedFailuresCount; + private final String request; private final String result; private final CountDownLatch firstAttemptFinished = new CountDownLatch(1); - FailingCallable(int expectedFailuresCount, String result, ApiTracer tracer) { + FailingCallable(int expectedFailuresCount, String request, String result, ApiTracer tracer) { + this.request = request; this.tracer = tracer; this.expectedFailuresCount = expectedFailuresCount; this.result = result; @@ -80,7 +82,7 @@ public String call() throws Exception { try { int attemptNumber = attemptsCount.getAndIncrement(); - tracer.attemptStarted(attemptNumber); + tracer.attemptStarted(request, attemptNumber); if (attemptNumber < expectedFailuresCount) { throw new CustomException(); diff --git a/gax/src/test/java/com/google/api/gax/retrying/ScheduledRetryingExecutorTest.java b/gax/src/test/java/com/google/api/gax/retrying/ScheduledRetryingExecutorTest.java index 23dff4a30..76793ec98 100644 --- a/gax/src/test/java/com/google/api/gax/retrying/ScheduledRetryingExecutorTest.java +++ b/gax/src/test/java/com/google/api/gax/retrying/ScheduledRetryingExecutorTest.java @@ -88,7 +88,7 @@ public void testSuccessWithFailuresPeekAttempt() throws Exception { final int maxRetries = 100; ScheduledExecutorService localExecutor = Executors.newSingleThreadScheduledExecutor(); - FailingCallable callable = new FailingCallable(15, "SUCCESS", tracer); + FailingCallable callable = new FailingCallable(15, "request", "SUCCESS", tracer); RetrySettings retrySettings = FAST_RETRY_SETTINGS @@ -139,7 +139,7 @@ public void testSuccessWithFailuresGetAttempt() throws Exception { final int maxRetries = 100; ScheduledExecutorService localExecutor = Executors.newSingleThreadScheduledExecutor(); - FailingCallable callable = new FailingCallable(15, "SUCCESS", tracer); + FailingCallable callable = new FailingCallable(15, "request", "SUCCESS", tracer); RetrySettings retrySettings = FAST_RETRY_SETTINGS .toBuilder() @@ -192,7 +192,7 @@ public void testCancelGetAttempt() throws Exception { ScheduledExecutorService localExecutor = Executors.newSingleThreadScheduledExecutor(); final int maxRetries = 100; - FailingCallable callable = new FailingCallable(maxRetries - 1, "SUCCESS", tracer); + FailingCallable callable = new FailingCallable(maxRetries - 1, "request", "SUCCESS", tracer); RetrySettings retrySettings = FAST_RETRY_SETTINGS .toBuilder() @@ -249,7 +249,7 @@ public void testCancelGetAttempt() throws Exception { public void testCancelOuterFutureAfterStart() throws Exception { for (int executionsCount = 0; executionsCount < EXECUTIONS_COUNT; executionsCount++) { ScheduledExecutorService localExecutor = Executors.newSingleThreadScheduledExecutor(); - FailingCallable callable = new FailingCallable(4, "SUCCESS", tracer); + FailingCallable callable = new FailingCallable(4, "requset", "SUCCESS", tracer); RetrySettings retrySettings = FAST_RETRY_SETTINGS .toBuilder() @@ -276,7 +276,7 @@ public void testCancelOuterFutureAfterStart() throws Exception { @Test public void testCancelIsTraced() throws Exception { ScheduledExecutorService localExecutor = Executors.newSingleThreadScheduledExecutor(); - FailingCallable callable = new FailingCallable(4, "SUCCESS", tracer); + FailingCallable callable = new FailingCallable(4, "request", "SUCCESS", tracer); RetrySettings retrySettings = FAST_RETRY_SETTINGS .toBuilder() @@ -305,7 +305,7 @@ public void testCancelProxiedFutureAfterStart() throws Exception { // this is a heavy test, which takes a lot of time, so only few executions. for (int executionsCount = 0; executionsCount < 2; executionsCount++) { ScheduledExecutorService localExecutor = Executors.newSingleThreadScheduledExecutor(); - FailingCallable callable = new FailingCallable(5, "SUCCESS", tracer); + FailingCallable callable = new FailingCallable(5, "request", "SUCCESS", tracer); RetrySettings retrySettings = FAST_RETRY_SETTINGS .toBuilder() diff --git a/gax/src/test/java/com/google/api/gax/tracing/TracedCallableTest.java b/gax/src/test/java/com/google/api/gax/tracing/TracedCallableTest.java index 1a2454d5b..834b357e4 100644 --- a/gax/src/test/java/com/google/api/gax/tracing/TracedCallableTest.java +++ b/gax/src/test/java/com/google/api/gax/tracing/TracedCallableTest.java @@ -111,7 +111,7 @@ public void testNonRetriedCallable() throws Exception { ApiFuture future = callable.futureCall("Is your refrigerator running?", callContext); verify(tracerFactory, times(1)).newTracer(parentTracer, SPAN_NAME, OperationType.Unary); - verify(tracer, times(1)).attemptStarted(anyInt()); + verify(tracer, times(1)).attemptStarted(anyString(), anyInt()); verify(tracer, times(1)).attemptSucceeded(); verify(tracer, times(1)).operationSucceeded(); verifyNoMoreInteractions(tracer); diff --git a/samples/pom.xml b/samples/pom.xml index 5a20b4fb6..51c4a67c3 100644 --- a/samples/pom.xml +++ b/samples/pom.xml @@ -14,13 +14,13 @@ com.google.api gax - 2.6.0 + 2.7.0 com.google.api gax-grpc - 2.6.0 + 2.7.0 com.google.auto.value diff --git a/versions.txt b/versions.txt index bec7d7db0..56ddc2969 100644 --- a/versions.txt +++ b/versions.txt @@ -1,8 +1,8 @@ # Format: # module:released-version:current-version -gax:2.6.0:2.6.0 -gax-bom:2.6.0:2.6.0 -gax-grpc:2.6.0:2.6.0 -gax-httpjson:0.91.0:0.91.0 -benchmark:0.76.0:0.76.0 +gax:2.7.0:2.7.0 +gax-bom:2.7.0:2.7.0 +gax-grpc:2.7.0:2.7.0 +gax-httpjson:0.92.0:0.92.0 +benchmark:0.77.0:0.77.0