高级用法

本指南概述了如何自定义 Java 客户端库的多个更高级方面。常见的模式是,其中许多功能都依赖于底层 Callable,而不是标准方法。通常,Callable 适合用于查找此处未记录的其他 per-RPC 功能。

超时

Java 库提供了一个用于按调用级别设置超时的接口。默认值根据 googleads_grpc_service_config.json 中的 method_config/timeout 设置设定。如果您需要对 API 调用最长时间施加较短的限制,请设置一个较低的值。

如需使用此功能,您应直接使用 Callable 对象。例如,如果调用 GoogleAdsService.searchStream(),超时将设置为:

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)));
}

您可以将超时设置为 2 小时或更长时间,但 API 可能仍会将超长时间运行的请求超时并返回 DEADLINE_EXCEEDED 错误。如果这成为问题,通常最好拆分查询并并行执行数据块;这样可以避免长时间运行的请求失败,而恢复的唯一方法是从头开始触发请求。

重试设置

Java 库还提供了在每次调用级别配置重试设置的 Surface。如需使用此功能,您应直接使用 Callable 对象。例如,如果调用 GoogleAdsService.searchStream(),重试设置将配置如下:

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

启动时间性能优化

首次创建 GoogleAdsClient 实例时,您可能会注意到略有延迟。这是由于服务的流畅接口 (GoogleAdsClient.getVersionXX()) 会同时加载所有 API 类,以提供更方便的服务类的构建机制。

如果第一个请求性能位于应用的关键路径中,您应该按照以下步骤操作:

  1. 请在启动时创建 GoogleAdsClient,然后再处理用户请求。

  2. 在该进程启动时,向 Google Ads API 发送一些预热请求。例如:

    // 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.
        }
      }
    }
    

每个进程只需要运行一次预热请求。后续每次创建服务客户端时,都会自动重用预加载的类。

重复使用服务客户端

您应该在可行的情况下重复使用服务客户端实例,因为每次调用 GoogleAdsClient.getVersionXXX().createYYYServiceClient() 都会创建一个新的 TCP 连接。

您必须确保在不再需要客户端时将其关闭。这可以在 try-with-resources 块中完成,或通过对服务客户端调用 close() 来实现。

如果您尝试使用封闭式服务客户端发出 API 请求,服务客户端方法将抛出 java.util.concurrent.RejectedExecutionException

如果 JAR 超过 32 MB,App Engine 将无法部署

对于每个上传的文件,App Engine 有 32 MB 的配额。google-ads 的 JAR 会比该值大很多,使用 Shade/shadow jar 部署时更是如此。如果您手动部署 JAR,可能会遇到如下错误:

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

请改为使用 App Engine Gradle 插件Maven 插件进行部署。 每个 JAR 都有一个 enableJarSplitting 选项,这会将每个 jar 文件拆分为 10 MB 的区块,然后改为上传这些区块。

影子依赖项

如果您项目的依赖项与库的依赖项冲突,则应使用以下命令之一检查项目的依赖项,然后根据需要修改项目的依赖项。

Maven

mvn dependency:tree

Gradle

./gradlew dependencies

如果解决依赖项冲突不可行,您可以改为依赖于库的shaded版本。

Maven

<dependency>
  <groupId>com.google.api-ads</groupId>
  <artifactId>google-ads-shadowjar</artifactId>
  <version>29.0.0</version>
</dependency>

Gradle

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