Page Summary
-
Advanced features in the Java client library often rely on the underlying
Callableobject. -
You can set per-call timeouts and configure retry settings using the callable object.
-
To improve startup performance, create the
GoogleAdsClientinstance early and send warm-up requests. -
Reuse service client instances where possible to avoid creating new TCP connections, and close them when finished.
-
For App Engine deployments, use the Gradle or Maven plugin with
enableJarSplittingto handle large JAR files. -
Address dependency conflicts by inspecting dependencies or using the shaded version of the library.
This guide outlines how to customize several of the more advanced aspects of the
Java client library. A common pattern is that many of these features rely on the
underlying Callable rather than the standard convenience methods. The callable
is generally a good place to look for other per-RPC features that aren't
documented here.
Timeout
The Java library provides a surface for setting timeouts on a per-call level.
The default value is set based on the method_config/timeout setting in
googleads_grpc_service_config.json. Set a lower value
if you need to enforce a shorter limit on the maximum time for an API call.
To use this feature, call the Callable object directly. For example, when
calling GoogleAdsService.searchStream(), set the timeout as follows:
try (GoogleAdsServiceClient googleAdsServiceClient =
googleAdsClient.getLatestVersion().createGoogleAdsServiceClient()) {
// Constructs the SearchGoogleAdsStreamRequest.
SearchGoogleAdsStreamRequest request =
SearchGoogleAdsStreamRequest.newBuilder()
.setCustomerId(Long.toString(customerId))
.setQuery("SELECT campaign.id, campaign.name FROM campaign")
.build();
// Executes the API call with a timeout of 5 minutes.
ServerStream<SearchGoogleAdsStreamResponse> stream =
googleAdsServiceClient
.searchStreamCallable()
.call(
request,
GrpcCallContext.createDefault()
.withTimeout(Duration.of(5, ChronoUnit.MINUTES)));
for (SearchGoogleAdsStreamResponse response : stream) {
// Processes the response rows.
}
}
You can set the timeout to 2 hours or more, but the API may still time out
extremely long-running requests and return a
DEADLINE_EXCEEDED error.
If this becomes an issue, it is usually best to split the query up and
execute the chunks in parallel; this avoids the situation where a long-running
request fails and the only way to recover is to trigger the request again from
the start.
Retry settings
The Java library also provides a surface for configuring retry settings on a
per-call level. To use this feature, call the Callable object directly. For
example, when calling GoogleAdsService.searchStream(), configure the retry
settings as follows:
try (GoogleAdsServiceClient googleAdsServiceClient =
googleAdsClient.getLatestVersion().createGoogleAdsServiceClient()) {
SearchGoogleAdsStreamRequest request =
SearchGoogleAdsStreamRequest.newBuilder()
.setCustomerId(Long.toString(customerId))
.setQuery("SELECT campaign.id, campaign.name FROM campaign")
.build();
// Creates a context object with the custom retry settings.
GrpcCallContext context =
GrpcCallContext.createDefault()
.withRetrySettings(
RetrySettings.newBuilder()
.setInitialRetryDelay(Duration.ofMillis(10L))
.setMaxRetryDelay(Duration.ofSeconds(10L))
.setRetryDelayMultiplier(1.4)
.setMaxAttempts(10)
.setLogicalTimeout(Duration.ofSeconds(30L))
.build());
// Issues the streaming search request.
ServerStream<SearchGoogleAdsStreamResponse> stream =
googleAdsServiceClient.searchStreamCallable().call(request, context);
for (SearchGoogleAdsStreamResponse response : stream) {
// Processes the response rows.
}
}
Startup time performance optimization
You may notice a small delay the first time a GoogleAdsClient instance is
created. This is due to the fluent interface for services
(GoogleAdsClient.getLatestVersion()), which loads the API service classes at
once to provide a convenient mechanism for constructing service clients.
If the first request performance is on the critical path for your application, follow these steps:
Create the
GoogleAdsClienton startup, before serving user requests.Send a few warm-up requests to the Google Ads API when the process first starts. For example:
// Runs some warm-up requests. try (GoogleAdsServiceClient googleAdsServiceClient = googleAdsClient.getLatestVersion().createGoogleAdsServiceClient()) { // Runs 5 warm-up requests. In our profiling we see that 90% of // performance loss is only experienced on the first API call. After 3 // subsequent calls we saw a negligible improvement in performance. for (int i = 0; i < 5; ++i) { // Warm-up queries are run with a nonexistent CID so the calls will // fail. If you have a CID that you know will be accessible with the // OAuth credentials provided you may want to provide that instead and // avoid the try-catch. try { googleAdsServiceClient.search("-1", "Warm-up query"); } catch (ApiException ex) { // Do nothing, we're expecting this to fail. } } }
The warm-up requests only need to be run once per process. Every subsequent service client creation automatically reuses the preloaded classes.
Service client reuse
You should reuse service client instances where practical because each call to
GoogleAdsClient.getLatestVersion().createYYYServiceClient() (or a
version-specific accessor such as getVersion25())
creates a new underlying connection and associated resources.
Make sure that you close the service client when it's no longer required. You
can do this in a try-with-resources block or by calling
close() on the service client.
If you attempt to use a closed service client to make API requests, the service
client method throws a java.util.concurrent.RejectedExecutionException.
App Engine fails to deploy if JAR > 32 MB
App Engine has a quota of 32 MB for each uploaded file. The JAR for google-ads
is considerably larger than this, especially when using shade or shadow JAR
deployments. If you deploy JARs manually, you might get errors such as:
ERROR: (gcloud.app.deploy) Cannot upload file [<your-app>/WEB-INF/lib/google-ads-46.1.0.jar],
which has size [66095767] (greater than maximum allowed size of [33554432])
Instead, deploy using the App Engine Gradle plugin or
Maven plugin. Each plugin provides an enableJarSplitting
option that splits each JAR into 10 MB chunks and uploads those instead.
Shadow dependencies
If your project has dependencies that conflict with the library's dependencies, inspect your project's dependency hierarchy using one of the following commands, and then modify your project's dependencies as needed (or use the Bill of Materials):
Maven
mvn dependency:treeGradle
./gradlew dependenciesIf resolving dependency conflicts is infeasible, you can depend on the shaded version of the library instead:
Maven
<dependency> <groupId>com.google.api-ads</groupId> <artifactId>google-ads-shadowjar</artifactId> <version>46.1.0</version> </dependency>
Gradle
implementation 'com.google.api-ads:google-ads-shadowjar:46.1.0'