Advanced usage

  • Advanced features in the Java client library often rely on the underlying Callable object.

  • You can set per-call timeouts and configure retry settings using the callable object.

  • To improve startup performance, create the GoogleAdsClient instance 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 enableJarSplitting to 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:

  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 (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: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>46.1.0</version>
</dependency>

Gradle

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