Advanced usage

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 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 you should use the callable object directly. For example, if calling GoogleAdsService.searchStream(), the timeout would be set as:

try (GoogleAdsServiceClient googleAdsServiceClient =
    googleAdsClient.getLatestVersion().createGoogleAdsServiceClient()) {
  // Constructs the SearchGoogleAdsStreamRequest.
  SearchGoogleAdsStreamRequest request = ...

  // Executes the API call, with a timeout of 5 minutes.
  ServerStream<SearchGoogleAdsStreamResponse> result = googleAdsServiceClient
      .searchStreamCallable()
      .call(request,
          GrpcCallContext.createDefault().withTimeout(Duration.of(5, ChronoUnit.MINUTES)));
}

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 you should use the callable object directly. For example, if calling GoogleAdsService.searchStream(), the retry settings would be configured as follows:

// 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());

// Creates and issues a search Google Ads stream request.
ServerStream<SearchGoogleAdsStreamResponse> stream =
    googleAdsServiceClient.searchStreamCallable().call(request, context);

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.getVersionXX()), which loads all the API classes at once in order to provide a more convenient mechanism for constructing service classes.

If the first request performance is in the critical path for your application, you should follow these steps:

  1. Create the GoogleAdsClient on startup, before serving user requests.

  2. 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 (GoogleAdsException 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 will automatically reuse the preloaded classes.

Service client reuse

You should reuse service client instances where practical since each call to GoogleAdsClient.getVersionXXX().createYYYServiceClient() will create a new TCP connection.

You must make sure that you close the client when it's no longer required. This can be done 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 will throw 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 will be considerably bigger than this, even moreso using shade/shadow jar deployments. If you deploy jars by hand, you might get errors like:

ERROR: (gcloud.app.deploy) Cannot upload file [<your-app>/WEB-INF/lib/google-ads-34.0.0.jar],
which has size [66095767] (greater than maximum allowed size of [33554432])

Instead, deploy using the AppEngine Gradle plugin or Maven plugin. Each has an option for enableJarSplitting which will split each jar into 10 MB chunks and upload those instead.

Shadow dependencies

If your project has dependencies that conflict with the library's, you should inspect your project's dependencies using one of the following commands, then modify your project's dependencies as needed.

Maven

mvn dependency:tree

Gradle

./gradlew dependencies

If 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>34.0.0</version>
</dependency>

Gradle

implementation 'com.google.api-ads:google-ads-shadowjar:34.0.0'