부분 실패

Google Ads API의 부분적 실패 기능을 사용하면 요청 내에서 성공한 작업을 커밋하는 동시에 실패한 작업에 대해서만 오류를 반환할 수 있습니다. 부분적 실패라고 하는 이 기능을 사용하면 실패한 작업을 마지막에 별도로 처리할 수 있습니다. 이 기능은 여러 Google Ads API 서비스의 가져오기 이외의 메서드에서 사용할 수 있습니다.

기술 세부정보

이 기능을 활용하려면 사용하려는 메서드의 partialFailure 매개변수를 설정하세요. 이 매개변수는 클라이언트 라이브러리마다 약간 다를 수 있습니다. 예를 들어 MutateAdGroups를 사용하여 요청을 전송할 때 이 기능을 사용 설정하려면 다음 단계를 따르세요.

자바

mutateAdGroups(String.valueOf(customerId), operations, true)

C#

MutateAdGroups(customerId.ToString(), operations, true, false)

PHP

mutateAdGroups($customerId, $operations, ['partialFailure' => true])

Python

mutate_ad_groups(customer_id, operations, partial_failure=True)

Ruby

mutate_ad_groups(customer_id, operations, partial_failure: true)

Perl

mutate({customerId => $customer_id, operations => $operations, partialFailure => 'true'})

서비스는 오류가 없는 작업을 실행합니다. 성공한 작업의 결과와 실패한 작업의 오류를 반환합니다.

사용

계정에 광고 그룹 집합을 추가해야 하지만 일부 광고 그룹에 문제가 있을 수 있다고 가정해 보겠습니다. 유효한 광고 그룹을 만들되 실패한 광고 그룹은 오류와 함께 반환되도록 하려고 합니다.

부분적 실패를 피해야 하는 경우

상호 의존적인 작업이 있는 요청에는 부분적 실패를 사용하면 안 됩니다.

예를 들어 실적 최대화 캠페인과 같이 단일 요청에서 여러 리소스를 만들어야 하는 복잡한 항목을 만드는 경우 부분적 실패를 사용하면 안 됩니다. 실적 최대화 캠페인을 처음 만들려면 동일한 요청에서 CampaignCampaignAsset 리소스를 만들어야 합니다. Campaign 생성이 실패하면 CampaignAsset 생성도 실패하며 요청을 단일 원자적 실패로 처리해야 합니다.

또 다른 예로 필수 애셋을 처음 추가할 때는 부분적 실패를 사용하지 마세요.AssetGroup 애셋 그룹은 애셋 없이 또는 모든 필수 애셋과 함께 만들 수 있습니다. 애셋 그룹에 애셋을 처음 추가할 때는 별도의 요청에서 한 번에 하나씩 추가할 수 없습니다. 모든 애셋을 하나의 요청에 포함해야 하며 부분적 실패를 사용하면 안 됩니다. 애셋 그룹에 필요한 모든 애셋이 포함된 후에는 애셋을 한 번에 하나씩 추가하거나 삭제할 수 있으며 이러한 요청은 부분적 실패를 사용할 수 있습니다.

부분적 실패가 적절한지 확인하려면 동일한 요청 내에서 교차 작업 리소스 참조에 임시 ID가 필요한지 확인하세요. 그렇다면 부분적 실패를 사용하면 안 됩니다. 두 번째 작업의 성공 여부는 첫 번째 작업의 성공 여부에 달려 있기 때문입니다.

작업을 만들고 API 호출하기

변경 작업을 만들고 평소와 같이 API를 호출합니다.

자바

private MutateAdGroupsResponse createAdGroups(
    GoogleAdsClient googleAdsClient, long customerId, long campaignId) {
  // This AdGroup should be created successfully - assuming the campaign in the params exists.
  AdGroup group1 =
      AdGroup.newBuilder()
          .setCampaign(ResourceNames.campaign(customerId, campaignId))
          .setName("Valid AdGroup: " + getPrintableDateTime())
          .build();
  // This AdGroup will always fail - campaign ID 0 in resource names is never valid.
  AdGroup group2 =
      AdGroup.newBuilder()
          .setCampaign(ResourceNames.campaign(customerId, 0L))
          .setName("Broken AdGroup: " + getPrintableDateTime())
          .build();
  // This AdGroup will always fail - duplicate ad group names are not allowed.
  AdGroup group3 =
      AdGroup.newBuilder()
          .setCampaign(ResourceNames.campaign(customerId, campaignId))
          .setName(group1.getName())
          .build();

  AdGroupOperation op1 = AdGroupOperation.newBuilder().setCreate(group1).build();
  AdGroupOperation op2 = AdGroupOperation.newBuilder().setCreate(group2).build();
  AdGroupOperation op3 = AdGroupOperation.newBuilder().setCreate(group3).build();

  try (AdGroupServiceClient service =
      googleAdsClient.getLatestVersion().createAdGroupServiceClient()) {
    // Issues the mutate request, setting partialFailure=true.
    return service.mutateAdGroups(
        MutateAdGroupsRequest.newBuilder()
            .setCustomerId(String.valueOf(customerId))
            .setCustomerId(Long.toString(customerId))
            .addAllOperations(Arrays.asList(op1, op2, op3))
            .setPartialFailure(true)
            .build());
  }
}
      

C#

private static MutateAdGroupsResponse CreateAdGroups(GoogleAdsClient client,
    long customerId, long campaignId)
{
    // Get the AdGroupServiceClient.
    AdGroupServiceClient adGroupService = client.GetService(Services.V24.AdGroupService);

    string validAdGroupName = "Valid AdGroup: " + ExampleUtilities.GetRandomString();

    AdGroupOperation[] operations = new AdGroupOperation[]
    {
        // This operation will be successful, assuming the campaign specified in
        // campaignId parameter is correct.
        new AdGroupOperation()
        {
            Create = new AdGroup()
            {
                Campaign = ResourceNames.Campaign(customerId, campaignId),
                Name = validAdGroupName
            }
        },
        // This operation will fail since we are using campaign ID = 0, which results
        // in an invalid resource name.
        new AdGroupOperation()
        {
            Create = new AdGroup()
            {
                Campaign = ResourceNames.Campaign(customerId, 0),
                Name = "Broken AdGroup: " + ExampleUtilities.GetRandomString()
            },
        },
        // This operation will fail since the ad group is using the same name as the ad
        // group from the first operation. Duplicate ad group names are not allowed.
        new AdGroupOperation()
        {
            Create = new AdGroup()
            {
                Campaign = ResourceNames.Campaign(customerId, campaignId),
                Name = validAdGroupName
            }
        }
    };

    // Add the ad groups.
    MutateAdGroupsResponse response =
        adGroupService.MutateAdGroups(new MutateAdGroupsRequest()
        {
            CustomerId = customerId.ToString(),
            Operations = { operations },
            PartialFailure = true,
            ValidateOnly = false
        });
    return response;
}
      

PHP

private static function createAdGroups(
    GoogleAdsClient $googleAdsClient,
    int $customerId,
    int $campaignId
) {
    $campaignResourceName = ResourceNames::forCampaign($customerId, $campaignId);

    // This ad group should be created successfully - assuming the campaign in the params
    // exists.
    $adGroup1 = new AdGroup([
        'name' => 'Valid AdGroup #' . Helper::getPrintableDatetime(),
        'campaign' => $campaignResourceName
    ]);

    // This ad group will always fail - campaign ID 0 in the resource name is never valid.
    $adGroup2 = new AdGroup([
        'name' => 'Broken AdGroup #' . Helper::getPrintableDatetime(),
        'campaign' => ResourceNames::forCampaign($customerId, 0)
    ]);

    // This ad group will always fail - duplicate ad group names are not allowed.
    $adGroup3 = new AdGroup([
        'name' => $adGroup1->getName(),
        'campaign' => $campaignResourceName
    ]);

    $operations = [];

    $adGroupOperation1 = new AdGroupOperation();
    $adGroupOperation1->setCreate($adGroup1);
    $operations[] = $adGroupOperation1;

    $adGroupOperation2 = new AdGroupOperation();
    $adGroupOperation2->setCreate($adGroup2);
    $operations[] = $adGroupOperation2;

    $adGroupOperation3 = new AdGroupOperation();
    $adGroupOperation3->setCreate($adGroup3);
    $operations[] = $adGroupOperation3;

    // Issues the mutate request, enabling partial failure mode.
    $adGroupServiceClient = $googleAdsClient->getAdGroupServiceClient();
    return $adGroupServiceClient->mutateAdGroups(
        MutateAdGroupsRequest::build($customerId, $operations)->setPartialFailure(true)
    );
}
      

Python

def create_ad_groups(
    client: GoogleAdsClient, customer_id: str, campaign_id: str
) -> MutateAdGroupsResponse:
    """Creates three Ad Groups, two of which intentionally generate errors.

    Args:
        client: An initialized GoogleAdsClient instance.
        customer_id: A valid customer account ID.
        campaign_id: The ID for a campaign to create Ad Groups under.

    Returns: A MutateAdGroupsResponse message instance.
    """
    ad_group_service: AdGroupServiceClient = client.get_service(
        "AdGroupService"
    )
    campaign_service: CampaignServiceClient = client.get_service(
        "CampaignService"
    )
    resource_name: str = campaign_service.campaign_path(
        customer_id, campaign_id
    )

    invalid_resource_name: str = campaign_service.campaign_path(customer_id, 0)
    ad_group_operations: List[AdGroupOperation] = []

    # This AdGroup should be created successfully - assuming the campaign in
    # the params exists.
    ad_group_op1: AdGroupOperation = client.get_type("AdGroupOperation")
    ad_group_op1.create.name = f"Valid AdGroup: {uuid.uuid4()}"
    ad_group_op1.create.campaign = resource_name
    ad_group_operations.append(ad_group_op1)

    # This AdGroup will always fail - campaign ID 0 in resource names is
    # never valid.
    ad_group_op2: AdGroupOperation = client.get_type("AdGroupOperation")
    ad_group_op2.create.name = f"Broken AdGroup: {uuid.uuid4()}"
    ad_group_op2.create.campaign = invalid_resource_name
    ad_group_operations.append(ad_group_op2)

    # This AdGroup will always fail - duplicate ad group names are not allowed.
    ad_group_op3: AdGroupOperation = client.get_type("AdGroupOperation")
    ad_group_op3.create.name = ad_group_op1.create.name
    ad_group_op3.create.campaign = resource_name
    ad_group_operations.append(ad_group_op3)

    # Issue a mutate request, setting partial_failure=True.
    request: MutateAdGroupsRequest = client.get_type("MutateAdGroupsRequest")
    request.customer_id = customer_id
    request.operations = ad_group_operations
    request.partial_failure = True
    return ad_group_service.mutate_ad_groups(request=request)
      

Ruby

def add_ad_groups(customer_id, campaign_id)
  # GoogleAdsClient will read a config file from
  # ENV['HOME']/google_ads_config.rb when called without parameters
  client = Google::Ads::GoogleAds::GoogleAdsClient.new

  ad_groups = []
  # This ad group should be created successfully.
  ad_groups << client.resource.ad_group do |ag|
    ag.campaign = client.path.campaign(customer_id, campaign_id)
    ag.name = "Valid ad group: #{(Time.new.to_f * 1000).to_i}"
  end
  # This ad group should fail to create because it references an invalid campaign.
  ad_groups << client.resource.ad_group do |ag|
    ag.campaign = client.path.campaign(customer_id, 0)
    ag.name = "Invalid ad group: #{(Time.new.to_f * 1000).to_i}"
  end
  # This ad group should fail to create because it duplicates the name from the first one.
  ad_groups << client.resource.ad_group do |ag|
    ag.campaign = client.path.campaign(customer_id, campaign_id)
    ag.name = ad_groups.first.name
  end

  operations = ad_groups.map do |ag|
    client.operation.create_resource.ad_group(ag)
  end

  response = client.service.ad_group.mutate_ad_groups(
    customer_id: customer_id,
    operations: operations,
    partial_failure: true,
  )

  response.results.each_with_index do |ad_group, i|
    if ad_group.resource_name != ""
      puts("operations[#{i}] succeeded: Created ad group with id #{ad_group.resource_name}")
    end
  end

  failures = client.decode_partial_failure_error(response.partial_failure_error)
  failures.each do |failure|
    failure.errors.each do |error|
      human_readable_error_path = error
        .location
        .field_path_elements
        .map { |location_info|
          if location_info.index
            "#{location_info.field_name}[#{location_info.index}]"
          else
            "#{location_info.field_name}"
          end
        }.join(" > ")

      errmsg =  "error occured creating ad group #{human_readable_error_path}" \
        " with value: #{error.trigger.string_value}" \
        " because #{error.message.downcase}"
      puts errmsg
    end
  end
end
      

Perl

sub create_ad_groups {
  my ($api_client, $customer_id, $campaign_id) = @_;

  my $campaign_resource_name =
    Google::Ads::GoogleAds::V24::Utils::ResourceNames::campaign($customer_id,
    $campaign_id);

  # This ad group should be created successfully - assuming the campaign in the
  # params exists.
  my $ad_group1 = Google::Ads::GoogleAds::V24::Resources::AdGroup->new({
    name     => "Valid AdGroup: " . uniqid(),
    campaign => $campaign_resource_name
  });

  # This ad group will always fail - campaign ID 0 in the resource name is never
  # valid.
  my $ad_group2 = Google::Ads::GoogleAds::V24::Resources::AdGroup->new({
      name     => "Broken AdGroup: " . uniqid(),
      campaign => Google::Ads::GoogleAds::V24::Utils::ResourceNames::campaign(
        $customer_id, 0
      )});

  # This ad group will always fail - duplicate ad group names are not allowed.
  my $ad_group3 = Google::Ads::GoogleAds::V24::Resources::AdGroup->new({
    name     => $ad_group1->{name},
    campaign => $campaign_resource_name
  });

  # Create ad group operations.
  my $ad_group_operation1 =
    Google::Ads::GoogleAds::V24::Services::AdGroupService::AdGroupOperation->
    new({create => $ad_group1});
  my $ad_group_operation2 =
    Google::Ads::GoogleAds::V24::Services::AdGroupService::AdGroupOperation->
    new({create => $ad_group2});
  my $ad_group_operation3 =
    Google::Ads::GoogleAds::V24::Services::AdGroupService::AdGroupOperation->
    new({create => $ad_group3});

  # Issue the mutate request, enabling partial failure mode.
  my $ad_groups_response = $api_client->AdGroupService()->mutate({
    customerId => $customer_id,
    operations =>
      [$ad_group_operation1, $ad_group_operation2, $ad_group_operation3],
    partialFailure => "true"
  });

  return $ad_groups_response;
}
      

curl

반환된 응답에 부분적 실패 오류가 포함되어 있는지 확인

응답의 부분적 실패 오류가 비어 있지 않은지 확인하여 반환된 응답에 부분적 실패 오류가 포함되어 있는지 확인할 수 있습니다.

자바

private boolean checkIfPartialFailureErrorExists(MutateAdGroupsResponse response) {
  return response.hasPartialFailureError();
}
      

C#

private static bool CheckIfPartialFailureErrorExists(MutateAdGroupsResponse response)
{
    return response.PartialFailureError != null;
}
      

PHP

private static function checkIfPartialFailureErrorExists(MutateAdGroupsResponse $response)
{
    if ($response->hasPartialFailureError()) {
        printf("Partial failures occurred. Details will be shown below.%s", PHP_EOL);
    } else {
        printf(
            "All operations completed successfully. No partial failures to show.%s",
            PHP_EOL
        );
    }
}
      

Python

def is_partial_failure_error_present(response: MutateAdGroupsResponse) -> bool:
    """Checks whether a response message has a partial failure error.

    In Python the partial_failure_error attr is always present on a response
    message and is represented by a google.rpc.Status message. So we can't
    simply check whether the field is present, we must check that the code is
    non-zero. Error codes are represented by the google.rpc.Code proto Enum:
    https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto

    Args:
        response:  A MutateAdGroupsResponse message instance.

    Returns: A boolean, whether or not the response message has a partial
        failure error.
    """
    partial_failure: Any = getattr(response, "partial_failure_error", None)
    code: int = int(getattr(partial_failure, "code", 0))  # Default to 0 if None
    return code != 0
      

Ruby

failures = client.decode_partial_failure_error(response.partial_failure_error)
failures.each do |failure|
  failure.errors.each do |error|
    human_readable_error_path = error
      .location
      .field_path_elements
      .map { |location_info|
        if location_info.index
          "#{location_info.field_name}[#{location_info.index}]"
        else
          "#{location_info.field_name}"
        end
      }.join(" > ")

    errmsg =  "error occured creating ad group #{human_readable_error_path}" \
      " with value: #{error.trigger.string_value}" \
      " because #{error.message.downcase}"
    puts errmsg
  end
end
      

Perl

sub check_if_partial_failure_error_exists {
  my $ad_groups_response = shift;

  if ($ad_groups_response->{partialFailureError}) {
    print "Partial failures occurred. Details will be shown below.\n";
  } else {
    print
      "All operations completed successfully. No partial failures to show.\n";
  }
}
      

curl

성공한 작업과 실패한 작업 처리

요청의 작업이 성공하면 응답 메시지의 해당 결과(예: MutateAdGroupsResponseMutateAdGroupResult)에 일반적으로 리소스 이름이 포함됩니다.

작업이 실패하면 응답 메시지에 partial_failure_error 필드가 채워집니다. 해석 방법은 다음과 같습니다.

  • partial_failure_error 필드는 google.rpc.Status 유형입니다.

  • Status.details 필드는 Google Ads API의 부분적 실패 오류에 대해 정확히 하나의 요소를 포함하는 목록입니다.

  • 이 단일 요소는 Any 의 단일 인스턴스를 패킹하는 GoogleAdsFailure프로토입니다. 실패한 작업 수와 관계없이 하나의 GoogleAdsFailure 객체만 반환됩니다.

  • GoogleAdsFailure 객체에는 errors이라는 반복 필드가 포함되어 있습니다. GoogleAdsError 객체 목록입니다.

  • errors 목록의 각 GoogleAdsError는 실패한 작업 중 하나의 특정 오류를 나타냅니다. 오류 메시지, 오류 코드, 트리거와 같은 세부정보가 포함됩니다.

  • 특정 GoogleAdsError, 를 일으킨 원래 작업을 식별하려면 GoogleAdsError.location 필드를 검사하면 됩니다. 일반적으로 location.field_path_elements[0].index는 원래 요청의 작업에서 0부터 시작하는 색인에 해당합니다.

모든 클라이언트 라이브러리는 오류 처리를 간소화하는 GoogleAdsFailure 객체를 추출하고 GoogleAdsError 목록을 반복하는 유틸리티 함수를 제공합니다. 예는 다음 코드 스니펫을 참고하세요.

자바

private void printResults(MutateAdGroupsResponse response) {
  int operationIndex = 0;
  for (MutateAdGroupResult result : response.getResultsList()) {
    if (ErrorUtils.getInstance().isPartialFailureResult(result)) {
      // May throw on this line. Most likely this means the wrong version of the ErrorUtils
      // class has been used.
      GoogleAdsFailure googleAdsFailure = ErrorUtils.getInstance()
          .getGoogleAdsFailure(response.getPartialFailureError());

      for (GoogleAdsError error :
          ErrorUtils.getInstance()
              .getGoogleAdsErrors(operationIndex, googleAdsFailure)) {
        System.out.printf("Operation %d failed with error: %s%n", operationIndex, error);
      }
    } else {
      System.out.printf("Operation %d succeeded.%n", operationIndex);
    }
    ++operationIndex;
  }
}
      

C#

private void PrintResults(MutateAdGroupsResponse response)
{
    // Finds the failed operations by looping through the results.
    int operationIndex = 0;
    foreach (MutateAdGroupResult result in response.Results)
    {
        // This represents the result of a failed operation.
        if (result.IsEmpty())
        {
            List<GoogleAdsError> errors =
                response.PartialFailure.GetErrorsByOperationIndex(operationIndex);
            foreach (GoogleAdsError error in errors)
            {
                Console.WriteLine($"Operation {operationIndex} failed with " +
                    $"error: {error}.");
            }
        }
        else
        {
            Console.WriteLine($"Operation {operationIndex} succeeded.",
                operationIndex);
        }
        operationIndex++;
    }
}
      

PHP

private static function printResults(MutateAdGroupsResponse $response)
{
    // Finds the failed operations by looping through the results.
    $operationIndex = 0;
    foreach ($response->getResults() as $result) {
        /** @var AdGroup $result */
        if (PartialFailures::isPartialFailure($result)) {
            $errors = GoogleAdsErrors::fromStatus(
                $operationIndex,
                $response->getPartialFailureError()
            );
            foreach ($errors as $error) {
                printf(
                    "Operation %d failed with error: %s%s",
                    $operationIndex,
                    $error->getMessage(),
                    PHP_EOL
                );
            }
        } else {
            printf(
                "Operation %d succeeded: ad group with resource name '%s'.%s",
                $operationIndex,
                $result->getResourceName(),
                PHP_EOL
            );
        }
        $operationIndex++;
    }
}
      

Python

def print_results(
    client: GoogleAdsClient, response: MutateAdGroupsResponse
) -> None:
    """Prints partial failure errors and success messages from a response.

    This function shows how to retrieve partial_failure errors from a response
    message (in the case of this example the message will be of type
    MutateAdGroupsResponse) and how to unpack those errors to GoogleAdsFailure
    instances. It also shows that a response with partial failures may still
    contain successful requests, and that those messages should be parsed
    separately. As an example, a GoogleAdsFailure object from this example will
    be structured similar to:

    error_code {
      range_error: TOO_LOW
    }
    message: "Too low."
    trigger {
      string_value: ""
    }
    location {
      field_path_elements {
        field_name: "operations"
        index {
          value: 1
        }
      }
      field_path_elements {
        field_name: "create"
      }
      field_path_elements {
        field_name: "campaign"
      }
    }

    Args:
        client: an initialized GoogleAdsClient.
        response: a MutateAdGroupsResponse instance.
    """
    # Check for existence of any partial failures in the response.
    if is_partial_failure_error_present(response):
        print("Partial failures occurred. Details will be shown below.\n")
        # Prints the details of the partial failure errors.
        partial_failure: Any = getattr(response, "partial_failure_error", None)
        # partial_failure_error.details is a repeated field and iterable
        error_details: List[Any] = getattr(partial_failure, "details", [])

        for error_detail in error_details:
            # Retrieve an instance of the GoogleAdsFailure class from the client
            failure_message: Any = client.get_type("GoogleAdsFailure")
            # Parse the string into a GoogleAdsFailure message instance.
            # To access class-only methods on the message we retrieve its type.
            GoogleAdsFailure: Any = type(failure_message)
            failure_object: Any = GoogleAdsFailure.deserialize(
                error_detail.value
            )

            for error in failure_object.errors:
                # Construct and print a string that details which element in
                # the above ad_group_operations list failed (by index number)
                # as well as the error message and error code.
                print(
                    "A partial failure at index "
                    f"{error.location.field_path_elements[0].index} occurred "
                    f"\nError message: {error.message}\nError code: "
                    f"{error.error_code}"
                )
    else:
        print(
            "All operations completed successfully. No partial failure "
            "to show."
        )

    # In the list of results, operations from the ad_group_operation list
    # that failed will be represented as empty messages. This loop detects
    # such empty messages and ignores them, while printing information about
    # successful operations.
    for message in response.results:
        if not message:
            continue

        print(f"Created ad group with resource_name: {message.resource_name}.")
      

Ruby

failures = client.decode_partial_failure_error(response.partial_failure_error)
failures.each do |failure|
  failure.errors.each do |error|
    human_readable_error_path = error
      .location
      .field_path_elements
      .map { |location_info|
        if location_info.index
          "#{location_info.field_name}[#{location_info.index}]"
        else
          "#{location_info.field_name}"
        end
      }.join(" > ")

    errmsg =  "error occured creating ad group #{human_readable_error_path}" \
      " with value: #{error.trigger.string_value}" \
      " because #{error.message.downcase}"
    puts errmsg
  end
end
      

Perl

sub print_results {
  my $ad_groups_response = shift;

  # Find the failed operations by looping through the results.
  while (my ($operation_index, $result) =
    each @{$ad_groups_response->{results}})
  {
    if (is_partial_failure_result($result)) {
      my $google_ads_errors = get_google_ads_errors($operation_index,
        $ad_groups_response->{partialFailureError});

      foreach my $google_ads_error (@$google_ads_errors) {
        printf "Operation %d failed with error: %s\n", $operation_index,
          $google_ads_error->{message};
      }
    } else {
      printf "Operation %d succeeded: ad group with resource name '%s'.\n",
        $operation_index, $result->{resourceName};
    }
  }
}
      

curl

비동기 작업의 부분적 실패

OfflineUserDataJob과 같은 비동기 작업에 부분적 실패를 사용하는 경우 일부 또는 모든 작업을 작업에 추가하지 못하더라도 작업이 SUCCESS 상태를 반환할 수 있다는 점에 유의해야 합니다.

부분적 실패가 사용 설정된 경우 OfflineUserDataJob에 작업을 추가하려고 할 때 일부 작업이 잘못되면 이러한 작업은 partial_failure_error 필드의 AddOfflineUserDataJobOperationsResponse에 오류를 반환하지만 유효한 작업은 작업에 추가됩니다. 모든 작업이 잘못된 경우 partial_failure_error가 채워지지만 작업에 작업이 추가되지 않습니다.

RunOfflineUserDataJob으로 작업을 실행할 때 작업 에 작업이 포함되어 있지 않으면(예: 작업이 잘못되어 작업에 추가되지 않았기 때문에) SUCCESS 상태로 완료됩니다.

OfflineUserDataJob에 작업을 추가할 때 부분적 실패를 사용하는 경우 AddOfflineUserDataJobOperationsResponse에서 partial_failure_error 필드를 확인해야 합니다. 이 필드가 채워져 있으면 일부 또는 모든 작업이 작업에 추가되지 않았다는 의미입니다.

코드 예시

클라이언트 라이브러리ErrorHandling 폴더에는 이 기능을 사용하는 방법을 보여주는 다음 코드 예시가 포함되어 있습니다.

자바

// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.ads.googleads.examples.errorhandling;

import static com.google.ads.googleads.examples.utils.CodeSampleHelper.getPrintableDateTime;

import com.beust.jcommander.Parameter;
import com.google.ads.googleads.examples.utils.ArgumentNames;
import com.google.ads.googleads.examples.utils.CodeSampleParams;
import com.google.ads.googleads.lib.GoogleAdsClient;
import com.google.ads.googleads.v24.errors.GoogleAdsError;
import com.google.ads.googleads.v24.errors.GoogleAdsException;
import com.google.ads.googleads.v24.errors.GoogleAdsFailure;
import com.google.ads.googleads.v24.resources.AdGroup;
import com.google.ads.googleads.v24.services.AdGroupOperation;
import com.google.ads.googleads.v24.services.AdGroupServiceClient;
import com.google.ads.googleads.v24.services.MutateAdGroupResult;
import com.google.ads.googleads.v24.services.MutateAdGroupsRequest;
import com.google.ads.googleads.v24.services.MutateAdGroupsResponse;
import com.google.ads.googleads.v24.utils.ErrorUtils;
import com.google.ads.googleads.v24.utils.ResourceNames;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;

/**
 * Shows how to handle partial failures. There are several ways of detecting partial failures. This
 * highlights the top main detection options: empty results and error instances.
 *
 * <p>Access to the detailed error (<code>GoogleAdsFailure</code>) for each error is via a Any
 * proto. Deserializing these to retrieve the error details is may not be immediately obvious at
 * first, this example shows how to convert Any into <code>GoogleAdsFailure</code>.
 *
 * <p>Additionally, this example shows how to produce an error message for a specific failed
 * operation by looking up the failure details in the <code>GoogleAdsFailure</code> object.
 */
public class HandlePartialFailure {

  private static class HandlePartialFailureParams extends CodeSampleParams {

    @Parameter(names = ArgumentNames.CUSTOMER_ID, required = true)
    private Long customerId;

    @Parameter(names = ArgumentNames.CAMPAIGN_ID, required = true)
    private Long campaignId;
  }

  public static void main(String[] args) {
    HandlePartialFailureParams params = new HandlePartialFailureParams();
    if (!params.parseArguments(args)) {
      // Either pass the required parameters for this example on the command line, or insert them
      // into the code here. See the parameter class definition above for descriptions.
      params.customerId = Long.parseLong("INSERT_CUSTOMER_ID");
      params.campaignId = Long.parseLong("INSERT_CAMPAIGN_ID");
    }
    GoogleAdsClient googleAdsClient = null;
    try {
      googleAdsClient = GoogleAdsClient.newBuilder().fromPropertiesFile().build();
    } catch (FileNotFoundException fnfe) {
      System.err.printf(
          "Failed to load GoogleAdsClient configuration from file. Exception: %s%n", fnfe);
      System.exit(1);
    } catch (IOException ioe) {
      System.err.printf("Failed to create GoogleAdsClient. Exception: %s%n", ioe);
      System.exit(1);
    }

    try {
      new HandlePartialFailure().runExample(googleAdsClient, params.customerId, params.campaignId);
    } catch (GoogleAdsException gae) {
      // GoogleAdsException is the base class for most exceptions thrown by an API request.
      // Instances of this exception have a message and a GoogleAdsFailure that contains a
      // collection of GoogleAdsErrors that indicate the underlying causes of the
      // GoogleAdsException.
      System.err.printf(
          "Request ID %s failed due to GoogleAdsException. Underlying errors:%n",
          gae.getRequestId());
      int i = 0;
      for (GoogleAdsError googleAdsError : gae.getGoogleAdsFailure().getErrorsList()) {
        System.err.printf("  Error %d: %s%n", i++, googleAdsError);
      }
      System.exit(1);
    }
  }

  /** Runs the example. */
  public void runExample(GoogleAdsClient googleAdsClient, long customerId, long campaignId) {
    MutateAdGroupsResponse response = createAdGroups(googleAdsClient, customerId, campaignId);

    // Checks for existence of any partial failures in the response.
    if (checkIfPartialFailureErrorExists(response)) {
      System.out.println("Partial failures occurred.");
    } else {
      System.out.println("All operations completed successfully. No partial failures to show.");
      return;
    }

    // Finds the failed operations by looping through the results.
    printResults(response);
  }

  /**
   * Attempts to create 3 ad groups with partial failure enabled. One of the ad groups will succeed,
   * while the other will fail.
   */
  private MutateAdGroupsResponse createAdGroups(
      GoogleAdsClient googleAdsClient, long customerId, long campaignId) {
    // This AdGroup should be created successfully - assuming the campaign in the params exists.
    AdGroup group1 =
        AdGroup.newBuilder()
            .setCampaign(ResourceNames.campaign(customerId, campaignId))
            .setName("Valid AdGroup: " + getPrintableDateTime())
            .build();
    // This AdGroup will always fail - campaign ID 0 in resource names is never valid.
    AdGroup group2 =
        AdGroup.newBuilder()
            .setCampaign(ResourceNames.campaign(customerId, 0L))
            .setName("Broken AdGroup: " + getPrintableDateTime())
            .build();
    // This AdGroup will always fail - duplicate ad group names are not allowed.
    AdGroup group3 =
        AdGroup.newBuilder()
            .setCampaign(ResourceNames.campaign(customerId, campaignId))
            .setName(group1.getName())
            .build();

    AdGroupOperation op1 = AdGroupOperation.newBuilder().setCreate(group1).build();
    AdGroupOperation op2 = AdGroupOperation.newBuilder().setCreate(group2).build();
    AdGroupOperation op3 = AdGroupOperation.newBuilder().setCreate(group3).build();

    try (AdGroupServiceClient service =
        googleAdsClient.getLatestVersion().createAdGroupServiceClient()) {
      // Issues the mutate request, setting partialFailure=true.
      return service.mutateAdGroups(
          MutateAdGroupsRequest.newBuilder()
              .setCustomerId(String.valueOf(customerId))
              .setCustomerId(Long.toString(customerId))
              .addAllOperations(Arrays.asList(op1, op2, op3))
              .setPartialFailure(true)
              .build());
    }
  }

  /** Inspects a response to check for presence of partial failure errors. */
  private boolean checkIfPartialFailureErrorExists(MutateAdGroupsResponse response) {
    return response.hasPartialFailureError();
  }

  /** Displays the result from the mutate operation. */
  private void printResults(MutateAdGroupsResponse response) {
    int operationIndex = 0;
    for (MutateAdGroupResult result : response.getResultsList()) {
      if (ErrorUtils.getInstance().isPartialFailureResult(result)) {
        // May throw on this line. Most likely this means the wrong version of the ErrorUtils
        // class has been used.
        GoogleAdsFailure googleAdsFailure = ErrorUtils.getInstance()
            .getGoogleAdsFailure(response.getPartialFailureError());

        for (GoogleAdsError error :
            ErrorUtils.getInstance()
                .getGoogleAdsErrors(operationIndex, googleAdsFailure)) {
          System.out.printf("Operation %d failed with error: %s%n", operationIndex, error);
        }
      } else {
        System.out.printf("Operation %d succeeded.%n", operationIndex);
      }
      ++operationIndex;
    }
  }
}

      

C#

// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using CommandLine;
using Google.Ads.Gax.Examples;
using Google.Ads.Gax.Lib;
using Google.Ads.GoogleAds.Lib;
using Google.Ads.GoogleAds.V24.Errors;
using Google.Ads.GoogleAds.V24.Resources;
using Google.Ads.GoogleAds.V24.Services;
using System;
using System.Collections.Generic;

namespace Google.Ads.GoogleAds.Examples.V24
{
    /// <summary>
    /// This code example demonstrates how to handle partial failures.
    /// </summary>
    public class HandlePartialFailure : ExampleBase
    {
        /// <summary>
        /// Command line options for running the <see cref="HandlePartialFailure"/> example.
        /// </summary>
        public class Options : OptionsBase
        {
            /// <summary>
            /// The customer ID for which the call is made.
            /// </summary>
            [Option("customerId", Required = true, HelpText =
                "The customer ID for which the call is made.")]
            public long CustomerId { get; set; }

            /// <summary>
            /// ID of the campaign to which ad groups are added.
            /// </summary>
            [Option("campaignId", Required = true, HelpText =
                "ID of the campaign to which ad groups are added.")]
            public long CampaignId { get; set; }
        }

        /// <summary>
        /// Main method, to run this code example as a standalone application.
        /// </summary>
        /// <param name="args">The command line arguments.</param>
        public static void Main(string[] args)
        {
            Options options = ExampleUtilities.ParseCommandLine<Options>(args);

            HandlePartialFailure codeExample = new HandlePartialFailure();
            Console.WriteLine(codeExample.Description);
            codeExample.Run(new GoogleAdsClient(), options.CustomerId, options.CampaignId);
        }

        /// <summary>
        /// Returns a description about the code example.
        /// </summary>
        public override string Description =>
            "This code example demonstrates how to handle partial failures.";

        /// <summary>
        /// Runs the code example.
        /// </summary>
        /// <param name="client">The Google Ads client.</param>
        /// <param name="customerId">The customer ID for which the call is made.</param>
        /// <param name="campaignId">ID of the campaign to which ad groups are added.</param>
        public void Run(GoogleAdsClient client, long customerId, long campaignId)
        {
            try
            {
                MutateAdGroupsResponse response = CreateAdGroups(client, customerId, campaignId);

                // Checks for existence of any partial failures in the response.
                if (CheckIfPartialFailureErrorExists(response))
                {
                    Console.WriteLine("Partial failures occurred. Details will be shown below.");
                }
                else
                {
                    Console.WriteLine("All operations completed successfully. No partial " +
                        "failures to show.");
                    return;
                }

                // Finds the failed operations by looping through the results.
                PrintResults(response);
            }
            catch (GoogleAdsException e)
            {
                Console.WriteLine("Failure:");
                Console.WriteLine($"Message: {e.Message}");
                Console.WriteLine($"Failure: {e.Failure}");
                Console.WriteLine($"Request ID: {e.RequestId}");
                throw;
            }
        }

        /// <summary>
        /// Displays the result from the mutate operation.
        /// </summary>
        /// <param name="response">The mutate response from the Google Ads API server..</param>
        private void PrintResults(MutateAdGroupsResponse response)
        {
            // Finds the failed operations by looping through the results.
            int operationIndex = 0;
            foreach (MutateAdGroupResult result in response.Results)
            {
                // This represents the result of a failed operation.
                if (result.IsEmpty())
                {
                    List<GoogleAdsError> errors =
                        response.PartialFailure.GetErrorsByOperationIndex(operationIndex);
                    foreach (GoogleAdsError error in errors)
                    {
                        Console.WriteLine($"Operation {operationIndex} failed with " +
                            $"error: {error}.");
                    }
                }
                else
                {
                    Console.WriteLine($"Operation {operationIndex} succeeded.",
                        operationIndex);
                }
                operationIndex++;
            }
        }

        /// <summary>
        /// Inspects a response to check for presence of partial failure errors.
        /// </summary>
        /// <param name="response">The response.</param>
        /// <returns>True if there are partial failures, false otherwise.</returns>
        private static bool CheckIfPartialFailureErrorExists(MutateAdGroupsResponse response)
        {
            return response.PartialFailureError != null;
        }

        /// <summary>
        /// Attempts to create 3 ad groups with partial failure enabled. One of the ad groups
        /// will succeed, while the other will fail.
        /// </summary>
        /// <param name="client">The Google Ads client.</param>
        /// <param name="customerId">The customer ID for which the call is made.</param>
        /// <param name="campaignId">ID of the campaign to which ad groups are added.</param>
        /// <returns>The mutate response from the Google Ads server.</returns>
        private static MutateAdGroupsResponse CreateAdGroups(GoogleAdsClient client,
            long customerId, long campaignId)
        {
            // Get the AdGroupServiceClient.
            AdGroupServiceClient adGroupService = client.GetService(Services.V24.AdGroupService);

            string validAdGroupName = "Valid AdGroup: " + ExampleUtilities.GetRandomString();

            AdGroupOperation[] operations = new AdGroupOperation[]
            {
                // This operation will be successful, assuming the campaign specified in
                // campaignId parameter is correct.
                new AdGroupOperation()
                {
                    Create = new AdGroup()
                    {
                        Campaign = ResourceNames.Campaign(customerId, campaignId),
                        Name = validAdGroupName
                    }
                },
                // This operation will fail since we are using campaign ID = 0, which results
                // in an invalid resource name.
                new AdGroupOperation()
                {
                    Create = new AdGroup()
                    {
                        Campaign = ResourceNames.Campaign(customerId, 0),
                        Name = "Broken AdGroup: " + ExampleUtilities.GetRandomString()
                    },
                },
                // This operation will fail since the ad group is using the same name as the ad
                // group from the first operation. Duplicate ad group names are not allowed.
                new AdGroupOperation()
                {
                    Create = new AdGroup()
                    {
                        Campaign = ResourceNames.Campaign(customerId, campaignId),
                        Name = validAdGroupName
                    }
                }
            };

            // Add the ad groups.
            MutateAdGroupsResponse response =
                adGroupService.MutateAdGroups(new MutateAdGroupsRequest()
                {
                    CustomerId = customerId.ToString(),
                    Operations = { operations },
                    PartialFailure = true,
                    ValidateOnly = false
                });
            return response;
        }
    }
}

      

PHP

<?php

/**
 * Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

 namespace Google\Ads\GoogleAds\Examples\ErrorHandling;

require __DIR__ . '/../../vendor/autoload.php';

use GetOpt\GetOpt;
use Google\Ads\GoogleAds\Examples\Utils\ArgumentNames;
use Google\Ads\GoogleAds\Examples\Utils\ArgumentParser;
use Google\Ads\GoogleAds\Examples\Utils\Helper;
use Google\Ads\GoogleAds\Lib\V24\GoogleAdsClient;
use Google\Ads\GoogleAds\Lib\V24\GoogleAdsClientBuilder;
use Google\Ads\GoogleAds\Lib\V24\GoogleAdsException;
use Google\Ads\GoogleAds\Lib\OAuth2TokenBuilder;
use Google\Ads\GoogleAds\Util\V24\GoogleAdsErrors;
use Google\Ads\GoogleAds\Util\V24\PartialFailures;
use Google\Ads\GoogleAds\Util\V24\ResourceNames;
use Google\Ads\GoogleAds\V24\Errors\GoogleAdsError;
use Google\Ads\GoogleAds\V24\Resources\AdGroup;
use Google\Ads\GoogleAds\V24\Services\AdGroupOperation;
use Google\Ads\GoogleAds\V24\Services\MutateAdGroupsRequest;
use Google\Ads\GoogleAds\V24\Services\MutateAdGroupsResponse;
use Google\ApiCore\ApiException;

/**
 * Shows how to handle partial failures. There are several ways of detecting partial failures. This
 * highlights the top main detection options: empty results and error instances.
 *
 * <p>Access to the detailed error (<code>GoogleAdsFailure</code>) for each error is via a Any
 * proto. Deserializing these to retrieve the error details is may not be immediately obvious at
 * first, this example shows how to convert Any into <code>GoogleAdsFailure</code>.
 *
 * <p>Additionally, this example shows how to produce an error message for a specific failed
 * operation by looking up the failure details in the <code>GoogleAdsFailure</code> object.
 */
class HandlePartialFailure
{
    private const CUSTOMER_ID = 'INSERT_CUSTOMER_ID_HERE';
    private const CAMPAIGN_ID = 'INSERT_CAMPAIGN_ID_HERE';

    public static function main()
    {
        // Either pass the required parameters for this example on the command line, or insert them
        // into the constants above.
        $options = (new ArgumentParser())->parseCommandArguments([
            ArgumentNames::CUSTOMER_ID => GetOpt::REQUIRED_ARGUMENT,
            ArgumentNames::CAMPAIGN_ID => GetOpt::REQUIRED_ARGUMENT
        ]);

        // Generate a refreshable OAuth2 credential for authentication.
        $oAuth2Credential = (new OAuth2TokenBuilder())->fromFile()->build();

        // Construct a Google Ads client configured from a properties file and the
        // OAuth2 credentials above.
        $googleAdsClient = (new GoogleAdsClientBuilder())
            ->fromFile()
            ->withOAuth2Credential($oAuth2Credential)
            ->build();

        try {
            self::runExample(
                $googleAdsClient,
                $options[ArgumentNames::CUSTOMER_ID] ?: self::CUSTOMER_ID,
                $options[ArgumentNames::CAMPAIGN_ID] ?: self::CAMPAIGN_ID
            );
        } catch (GoogleAdsException $googleAdsException) {
            printf(
                "Request with ID '%s' has failed.%sGoogle Ads failure details:%s",
                $googleAdsException->getRequestId(),
                PHP_EOL,
                PHP_EOL
            );
            foreach ($googleAdsException->getGoogleAdsFailure()->getErrors() as $error) {
                /** @var GoogleAdsError $error */
                printf(
                    "\t%s: %s%s",
                    $error->getErrorCode()->getErrorCode(),
                    $error->getMessage(),
                    PHP_EOL
                );
            }
            exit(1);
        } catch (ApiException $apiException) {
            printf(
                "ApiException was thrown with message '%s'.%s",
                $apiException->getMessage(),
                PHP_EOL
            );
            exit(1);
        }
    }

    /**
     * Runs the example.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the customer ID
     * @param int $campaignId a campaign ID
     */
    public static function runExample(
        GoogleAdsClient $googleAdsClient,
        int $customerId,
        int $campaignId
    ) {
        $response = self::createAdGroups($googleAdsClient, $customerId, $campaignId);
        self::checkIfPartialFailureErrorExists($response);
        self::printResults($response);
    }

    /**
     * Create ad groups by enabling partial failure mode.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the customer ID
     * @param int $campaignId a campaign ID
     * @return MutateAdGroupsResponse
     */
    private static function createAdGroups(
        GoogleAdsClient $googleAdsClient,
        int $customerId,
        int $campaignId
    ) {
        $campaignResourceName = ResourceNames::forCampaign($customerId, $campaignId);

        // This ad group should be created successfully - assuming the campaign in the params
        // exists.
        $adGroup1 = new AdGroup([
            'name' => 'Valid AdGroup #' . Helper::getPrintableDatetime(),
            'campaign' => $campaignResourceName
        ]);

        // This ad group will always fail - campaign ID 0 in the resource name is never valid.
        $adGroup2 = new AdGroup([
            'name' => 'Broken AdGroup #' . Helper::getPrintableDatetime(),
            'campaign' => ResourceNames::forCampaign($customerId, 0)
        ]);

        // This ad group will always fail - duplicate ad group names are not allowed.
        $adGroup3 = new AdGroup([
            'name' => $adGroup1->getName(),
            'campaign' => $campaignResourceName
        ]);

        $operations = [];

        $adGroupOperation1 = new AdGroupOperation();
        $adGroupOperation1->setCreate($adGroup1);
        $operations[] = $adGroupOperation1;

        $adGroupOperation2 = new AdGroupOperation();
        $adGroupOperation2->setCreate($adGroup2);
        $operations[] = $adGroupOperation2;

        $adGroupOperation3 = new AdGroupOperation();
        $adGroupOperation3->setCreate($adGroup3);
        $operations[] = $adGroupOperation3;

        // Issues the mutate request, enabling partial failure mode.
        $adGroupServiceClient = $googleAdsClient->getAdGroupServiceClient();
        return $adGroupServiceClient->mutateAdGroups(
            MutateAdGroupsRequest::build($customerId, $operations)->setPartialFailure(true)
        );
    }

    /**
     * Check if there exists partial failure error in the given mutate ad group response.
     *
     * @param MutateAdGroupsResponse $response the mutate ad group response
     */
    private static function checkIfPartialFailureErrorExists(MutateAdGroupsResponse $response)
    {
        if ($response->hasPartialFailureError()) {
            printf("Partial failures occurred. Details will be shown below.%s", PHP_EOL);
        } else {
            printf(
                "All operations completed successfully. No partial failures to show.%s",
                PHP_EOL
            );
        }
    }

    /**
     * Print results of the given mutate ad group response. For those that are partial failure,
     * print all their errors with corresponding operation indices. For those that succeeded, print
     * the resource names of created ad groups.
     *
     * @param MutateAdGroupsResponse $response the mutate ad group response
     */
    private static function printResults(MutateAdGroupsResponse $response)
    {
        // Finds the failed operations by looping through the results.
        $operationIndex = 0;
        foreach ($response->getResults() as $result) {
            /** @var AdGroup $result */
            if (PartialFailures::isPartialFailure($result)) {
                $errors = GoogleAdsErrors::fromStatus(
                    $operationIndex,
                    $response->getPartialFailureError()
                );
                foreach ($errors as $error) {
                    printf(
                        "Operation %d failed with error: %s%s",
                        $operationIndex,
                        $error->getMessage(),
                        PHP_EOL
                    );
                }
            } else {
                printf(
                    "Operation %d succeeded: ad group with resource name '%s'.%s",
                    $operationIndex,
                    $result->getResourceName(),
                    PHP_EOL
                );
            }
            $operationIndex++;
        }
    }
}

HandlePartialFailure::main();

      

Python

#!/usr/bin/env python
# Copyright 2018 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""This shows how to handle responses that may include partial_failure errors."""

import argparse
import sys
import uuid
from typing import Any, List

from google.ads.googleads.client import GoogleAdsClient
from google.ads.googleads.errors import GoogleAdsException
from google.ads.googleads.v24.services.services.ad_group_service import (
    AdGroupServiceClient,
)
from google.ads.googleads.v24.services.services.campaign_service import (
    CampaignServiceClient,
)
from google.ads.googleads.v24.services.types.ad_group_service import (
    AdGroupOperation,
    MutateAdGroupsResponse,
    MutateAdGroupsRequest,
)


def main(client: GoogleAdsClient, customer_id: str, campaign_id: str) -> None:
    """Runs the example code, which demonstrates how to handle partial failures.

    The example creates three Ad Groups, two of which intentionally fail in
    order to generate a partial failure error. It also demonstrates how to
    properly identify a partial error and how to log the error messages.

    Args:
        client:  An initialized GoogleAdsClient instance.
        customer_id: A valid customer account ID.
        campaign_id: The ID for a campaign to create Ad Groups under.
    """
    try:
        ad_group_response: MutateAdGroupsResponse = create_ad_groups(
            client, customer_id, campaign_id
        )
    except GoogleAdsException as ex:
        print(
            f'Request with ID "{ex.request_id}" failed with status '
            f'"{ex.error.code().name}" and includes the following errors:'
        )
        for error in ex.failure.errors:
            print(f'\tError with message "{error.message}".')
            if error.location:
                for field_path_element in error.location.field_path_elements:
                    print(f"\t\tOn field: {field_path_element.field_name}")
        sys.exit(1)
    else:
        print_results(client, ad_group_response)


def create_ad_groups(
    client: GoogleAdsClient, customer_id: str, campaign_id: str
) -> MutateAdGroupsResponse:
    """Creates three Ad Groups, two of which intentionally generate errors.

    Args:
        client: An initialized GoogleAdsClient instance.
        customer_id: A valid customer account ID.
        campaign_id: The ID for a campaign to create Ad Groups under.

    Returns: A MutateAdGroupsResponse message instance.
    """
    ad_group_service: AdGroupServiceClient = client.get_service(
        "AdGroupService"
    )
    campaign_service: CampaignServiceClient = client.get_service(
        "CampaignService"
    )
    resource_name: str = campaign_service.campaign_path(
        customer_id, campaign_id
    )

    invalid_resource_name: str = campaign_service.campaign_path(customer_id, 0)
    ad_group_operations: List[AdGroupOperation] = []

    # This AdGroup should be created successfully - assuming the campaign in
    # the params exists.
    ad_group_op1: AdGroupOperation = client.get_type("AdGroupOperation")
    ad_group_op1.create.name = f"Valid AdGroup: {uuid.uuid4()}"
    ad_group_op1.create.campaign = resource_name
    ad_group_operations.append(ad_group_op1)

    # This AdGroup will always fail - campaign ID 0 in resource names is
    # never valid.
    ad_group_op2: AdGroupOperation = client.get_type("AdGroupOperation")
    ad_group_op2.create.name = f"Broken AdGroup: {uuid.uuid4()}"
    ad_group_op2.create.campaign = invalid_resource_name
    ad_group_operations.append(ad_group_op2)

    # This AdGroup will always fail - duplicate ad group names are not allowed.
    ad_group_op3: AdGroupOperation = client.get_type("AdGroupOperation")
    ad_group_op3.create.name = ad_group_op1.create.name
    ad_group_op3.create.campaign = resource_name
    ad_group_operations.append(ad_group_op3)

    # Issue a mutate request, setting partial_failure=True.
    request: MutateAdGroupsRequest = client.get_type("MutateAdGroupsRequest")
    request.customer_id = customer_id
    request.operations = ad_group_operations
    request.partial_failure = True
    return ad_group_service.mutate_ad_groups(request=request)


def is_partial_failure_error_present(response: MutateAdGroupsResponse) -> bool:
    """Checks whether a response message has a partial failure error.

    In Python the partial_failure_error attr is always present on a response
    message and is represented by a google.rpc.Status message. So we can't
    simply check whether the field is present, we must check that the code is
    non-zero. Error codes are represented by the google.rpc.Code proto Enum:
    https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto

    Args:
        response:  A MutateAdGroupsResponse message instance.

    Returns: A boolean, whether or not the response message has a partial
        failure error.
    """
    partial_failure: Any = getattr(response, "partial_failure_error", None)
    code: int = int(getattr(partial_failure, "code", 0))  # Default to 0 if None
    return code != 0


def print_results(
    client: GoogleAdsClient, response: MutateAdGroupsResponse
) -> None:
    """Prints partial failure errors and success messages from a response.

    This function shows how to retrieve partial_failure errors from a response
    message (in the case of this example the message will be of type
    MutateAdGroupsResponse) and how to unpack those errors to GoogleAdsFailure
    instances. It also shows that a response with partial failures may still
    contain successful requests, and that those messages should be parsed
    separately. As an example, a GoogleAdsFailure object from this example will
    be structured similar to:

    error_code {
      range_error: TOO_LOW
    }
    message: "Too low."
    trigger {
      string_value: ""
    }
    location {
      field_path_elements {
        field_name: "operations"
        index {
          value: 1
        }
      }
      field_path_elements {
        field_name: "create"
      }
      field_path_elements {
        field_name: "campaign"
      }
    }

    Args:
        client: an initialized GoogleAdsClient.
        response: a MutateAdGroupsResponse instance.
    """
    # Check for existence of any partial failures in the response.
    if is_partial_failure_error_present(response):
        print("Partial failures occurred. Details will be shown below.\n")
        # Prints the details of the partial failure errors.
        partial_failure: Any = getattr(response, "partial_failure_error", None)
        # partial_failure_error.details is a repeated field and iterable
        error_details: List[Any] = getattr(partial_failure, "details", [])

        for error_detail in error_details:
            # Retrieve an instance of the GoogleAdsFailure class from the client
            failure_message: Any = client.get_type("GoogleAdsFailure")
            # Parse the string into a GoogleAdsFailure message instance.
            # To access class-only methods on the message we retrieve its type.
            GoogleAdsFailure: Any = type(failure_message)
            failure_object: Any = GoogleAdsFailure.deserialize(
                error_detail.value
            )

            for error in failure_object.errors:
                # Construct and print a string that details which element in
                # the above ad_group_operations list failed (by index number)
                # as well as the error message and error code.
                print(
                    "A partial failure at index "
                    f"{error.location.field_path_elements[0].index} occurred "
                    f"\nError message: {error.message}\nError code: "
                    f"{error.error_code}"
                )
    else:
        print(
            "All operations completed successfully. No partial failure "
            "to show."
        )

    # In the list of results, operations from the ad_group_operation list
    # that failed will be represented as empty messages. This loop detects
    # such empty messages and ignores them, while printing information about
    # successful operations.
    for message in response.results:
        if not message:
            continue

        print(f"Created ad group with resource_name: {message.resource_name}.")


if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="Adds an ad group for specified customer and campaign id."
    )
    # The following argument(s) should be provided to run the example.
    parser.add_argument(
        "-c",
        "--customer_id",
        type=str,
        required=True,
        help="The Google Ads customer ID.",
    )
    parser.add_argument(
        "-i", "--campaign_id", type=str, required=True, help="The campaign ID."
    )
    args = parser.parse_args()

    # GoogleAdsClient will read the google-ads.yaml configuration file in the
    # home directory if none is specified.
    googleads_client: GoogleAdsClient = GoogleAdsClient.load_from_storage(
        version="v24"
    )

    main(googleads_client, args.customer_id, args.campaign_id)

      

Ruby

# Encoding: utf-8
#
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This code example shows how to deal with partial failures

require 'optparse'
require 'google/ads/google_ads'
require 'date'

def add_ad_groups(customer_id, campaign_id)
  # GoogleAdsClient will read a config file from
  # ENV['HOME']/google_ads_config.rb when called without parameters
  client = Google::Ads::GoogleAds::GoogleAdsClient.new

  ad_groups = []
  # This ad group should be created successfully.
  ad_groups << client.resource.ad_group do |ag|
    ag.campaign = client.path.campaign(customer_id, campaign_id)
    ag.name = "Valid ad group: #{(Time.new.to_f * 1000).to_i}"
  end
  # This ad group should fail to create because it references an invalid campaign.
  ad_groups << client.resource.ad_group do |ag|
    ag.campaign = client.path.campaign(customer_id, 0)
    ag.name = "Invalid ad group: #{(Time.new.to_f * 1000).to_i}"
  end
  # This ad group should fail to create because it duplicates the name from the first one.
  ad_groups << client.resource.ad_group do |ag|
    ag.campaign = client.path.campaign(customer_id, campaign_id)
    ag.name = ad_groups.first.name
  end

  operations = ad_groups.map do |ag|
    client.operation.create_resource.ad_group(ag)
  end

  response = client.service.ad_group.mutate_ad_groups(
    customer_id: customer_id,
    operations: operations,
    partial_failure: true,
  )

  response.results.each_with_index do |ad_group, i|
    if ad_group.resource_name != ""
      puts("operations[#{i}] succeeded: Created ad group with id #{ad_group.resource_name}")
    end
  end

  failures = client.decode_partial_failure_error(response.partial_failure_error)
  failures.each do |failure|
    failure.errors.each do |error|
      human_readable_error_path = error
        .location
        .field_path_elements
        .map { |location_info|
          if location_info.index
            "#{location_info.field_name}[#{location_info.index}]"
          else
            "#{location_info.field_name}"
          end
        }.join(" > ")

      errmsg =  "error occured creating ad group #{human_readable_error_path}" \
        " with value: #{error.trigger.string_value}" \
        " because #{error.message.downcase}"
      puts errmsg
    end
  end
end

if __FILE__ == $PROGRAM_NAME
  options = {}
  # The following parameter(s) should be provided to run the example. You can
  # either specify these by changing the INSERT_XXX_ID_HERE values below, or on
  # the command line.
  #
  # Parameters passed on the command line will override any parameters set in
  # code.
  #
  # Running the example with -h will print the command line usage.
  options[:customer_id] = 'INSERT_CUSTOMER_ID_HERE'
  options[:campaign_id] = 'INSERT_CAMPAIGN_ID_HERE'

  OptionParser.new do |opts|
    opts.banner = sprintf('Usage: ruby %s [options]', File.basename(__FILE__))

    opts.separator ''
    opts.separator 'Options:'

    opts.on('-C', '--customer-id CUSTOMER-ID', String, 'Customer ID') do |v|
      options[:customer_id] = v
    end

    opts.on('-c', '--campaign-id CAMPAIGN-ID', String, 'Ad Group ID') do |v|
      options[:campaign_id] = v
    end

    opts.separator ''
    opts.separator 'Help:'

    opts.on_tail('-h', '--help', 'Show this message') do
      puts opts
      exit
    end
  end.parse!

  begin
    add_ad_groups(
      options.fetch(:customer_id).tr("-", ""),
      options.fetch(:campaign_id),
    )
  rescue Google::Ads::GoogleAds::Errors::GoogleAdsError => e
    e.failure.errors.each do |error|
      STDERR.printf("Error with message: %s\n", error.message)
      if error.location
        error.location.field_path_elements.each do |field_path_element|
          STDERR.printf("\tOn field: %s\n", field_path_element.field_name)
        end
      end
      error.error_code.to_h.each do |k, v|
        next if v == :UNSPECIFIED
        STDERR.printf("\tType: %s\n\tCode: %s\n", k, v)
      end
    end
    raise
  end
end

      

Perl

#!/usr/bin/perl -w
#
# Copyright 2019, Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This example shows how to deal with partial failures. There are several ways
# of detecting partial failures. This example highlights the top main detection
# options: empty results and error instances.

use strict;
use warnings;
use utf8;

use FindBin qw($Bin);
use lib "$Bin/../../lib";
use Google::Ads::GoogleAds::Client;
use Google::Ads::GoogleAds::Utils::GoogleAdsHelper;
use Google::Ads::GoogleAds::Utils::PartialFailureUtils;
use Google::Ads::GoogleAds::V24::Resources::AdGroup;
use Google::Ads::GoogleAds::V24::Services::AdGroupService::AdGroupOperation;
use Google::Ads::GoogleAds::V24::Utils::ResourceNames;

use Getopt::Long qw(:config auto_help);
use Pod::Usage;
use Cwd          qw(abs_path);
use Data::Uniqid qw(uniqid);

# The following parameter(s) should be provided to run the example. You can
# either specify these by changing the INSERT_XXX_ID_HERE values below, or on
# the command line.
#
# Parameters passed on the command line will override any parameters set in
# code.
#
# Running the example with -h will print the command line usage.
my $customer_id = "INSERT_CUSTOMER_ID_HERE";
my $campaign_id = "INSERT_CAMPAIGN_ID_HERE";

sub handle_partial_failure {
  my ($api_client, $customer_id, $campaign_id) = @_;

  my $ad_groups_response =
    create_ad_groups($api_client, $customer_id, $campaign_id);
  check_if_partial_failure_error_exists($ad_groups_response);
  print_results($ad_groups_response);

  return 1;
}

# Creates ad groups by enabling partial failure mode.
sub create_ad_groups {
  my ($api_client, $customer_id, $campaign_id) = @_;

  my $campaign_resource_name =
    Google::Ads::GoogleAds::V24::Utils::ResourceNames::campaign($customer_id,
    $campaign_id);

  # This ad group should be created successfully - assuming the campaign in the
  # params exists.
  my $ad_group1 = Google::Ads::GoogleAds::V24::Resources::AdGroup->new({
    name     => "Valid AdGroup: " . uniqid(),
    campaign => $campaign_resource_name
  });

  # This ad group will always fail - campaign ID 0 in the resource name is never
  # valid.
  my $ad_group2 = Google::Ads::GoogleAds::V24::Resources::AdGroup->new({
      name     => "Broken AdGroup: " . uniqid(),
      campaign => Google::Ads::GoogleAds::V24::Utils::ResourceNames::campaign(
        $customer_id, 0
      )});

  # This ad group will always fail - duplicate ad group names are not allowed.
  my $ad_group3 = Google::Ads::GoogleAds::V24::Resources::AdGroup->new({
    name     => $ad_group1->{name},
    campaign => $campaign_resource_name
  });

  # Create ad group operations.
  my $ad_group_operation1 =
    Google::Ads::GoogleAds::V24::Services::AdGroupService::AdGroupOperation->
    new({create => $ad_group1});
  my $ad_group_operation2 =
    Google::Ads::GoogleAds::V24::Services::AdGroupService::AdGroupOperation->
    new({create => $ad_group2});
  my $ad_group_operation3 =
    Google::Ads::GoogleAds::V24::Services::AdGroupService::AdGroupOperation->
    new({create => $ad_group3});

  # Issue the mutate request, enabling partial failure mode.
  my $ad_groups_response = $api_client->AdGroupService()->mutate({
    customerId => $customer_id,
    operations =>
      [$ad_group_operation1, $ad_group_operation2, $ad_group_operation3],
    partialFailure => "true"
  });

  return $ad_groups_response;
}

# Checks if partial failure error exists in the given mutate ad group response.
sub check_if_partial_failure_error_exists {
  my $ad_groups_response = shift;

  if ($ad_groups_response->{partialFailureError}) {
    print "Partial failures occurred. Details will be shown below.\n";
  } else {
    print
      "All operations completed successfully. No partial failures to show.\n";
  }
}

# Prints results of the given mutate ad group response. For those that are partial
# failure, prints all their errors with corresponding operation indices. For those
# that succeeded, prints the resource names of created ad groups.
sub print_results {
  my $ad_groups_response = shift;

  # Find the failed operations by looping through the results.
  while (my ($operation_index, $result) =
    each @{$ad_groups_response->{results}})
  {
    if (is_partial_failure_result($result)) {
      my $google_ads_errors = get_google_ads_errors($operation_index,
        $ad_groups_response->{partialFailureError});

      foreach my $google_ads_error (@$google_ads_errors) {
        printf "Operation %d failed with error: %s\n", $operation_index,
          $google_ads_error->{message};
      }
    } else {
      printf "Operation %d succeeded: ad group with resource name '%s'.\n",
        $operation_index, $result->{resourceName};
    }
  }
}

# Don't run the example if the file is being included.
if (abs_path($0) ne abs_path(__FILE__)) {
  return 1;
}

# Get Google Ads Client, credentials will be read from ~/googleads.properties.
my $api_client = Google::Ads::GoogleAds::Client->new();

# By default examples are set to die on any server returned fault.
$api_client->set_die_on_faults(1);

# Parameters passed on the command line will override any parameters set in code.
GetOptions("customer_id=s" => \$customer_id, "campaign_id=i" => \$campaign_id);

# Print the help message if the parameters are not initialized in the code nor
# in the command line.
pod2usage(2) if not check_params($customer_id, $campaign_id);

# Call the example.
handle_partial_failure($api_client, $customer_id =~ s/-//gr, $campaign_id);

=pod

=head1 NAME

handle_partial_failure

=head1 DESCRIPTION

This example shows how to deal with partial failures. There are several ways of
detecting partial failures. This example highlights the top main detection
options: empty results and error instances.

=head1 SYNOPSIS

handle_partial_failure.pl [options]

    -help                       Show the help message.
    -customer_id                The Google Ads customer ID.
    -campaign_id                The campaign ID.

=cut

      

curl