Override Retry, Backoff, and Idempotency Policies

When it is safe to do so, the library automatically retries requests that fail due to a transient error. The library then uses exponential backoff to backoff before trying again. Which operations are considered safe to retry, which errors are treated as transient failures, the details of the exponential backoff algorithm, and for how long the library retries are all configurable via policies.

This document provides examples showing how to override the default policies.

The policies can be set when the *Connection object is created. The library provides default policies for any policy that is not set. The application can also override some (or all) policies when the *Client object is created. This can be useful if multiple *Client objects share the same *Connection object, but you want different retry behavior in some of the clients. Finally, the application can override some retry policies when calling a specific member function.

The library uses three different options to control the retry loop. The options have per-client names.

Configuring the transient errors and retry duration

The *RetryPolicyOption controls:

  • Which errors are to be treated as transient errors.
  • How long will the library will keep retrying transient errors.

You can provide your own class for this option. The library also provides two built-in policies:

  • *LimitedErrorCountRetryPolicy: stops retrying after a specified number of transient errors.
  • *LimitedTimeRetryPolicy: stops retrying after a specified time.
See Also

google::cloud::pubsub::RetryPolicyOption

See Also

google::cloud::pubsub::RetryPolicy

See Also

google::cloud::pubsub::LimitedTimeRetryPolicy

See Also

google::cloud::pubsub::LimitedErrorCountRetryPolicy

See Also

google::cloud::pubsub::SchemaServiceRetryPolicyOption

See Also

google::cloud::pubsub::SchemaServiceRetryPolicy

See Also

google::cloud::pubsub::SchemaServiceLimitedTimeRetryPolicy

See Also

google::cloud::pubsub::SchemaServiceLimitedErrorCountRetryPolicy

Controlling the backoff algorithm

The `*BackoffPolicyOption controls how long the client library will wait before retrying a request that failed with a transient error. You can provide your own class for this option.

The only built-in backoff policy is ExponentialBackoffPolicy. This class implements a truncated exponential backoff algorithm, with jitter. In summary, it doubles the current backoff time after each failure. The actual backoff time for an RPC is chosen at random, but never exceeds the current backoff. The current backoff is doubled after each failure, but never exceeds (or is "truncated") if it reaches a prescribed maximum.

See Also

google::cloud::pubsub::BackoffPolicyOption

See Also

google::cloud::pubsub::SchemaServiceBackoffPolicyOption

Controlling which operations are retryable

SchemaServiceClient supports the SchemaServiceConnectionIdempotencyPolicyOption to control which requests are idempotent, and therefore retryable. In all other cases the Pub/Sub library retries the operations.

For SchemaServiceClient only one built-in idempotency policy is provided by the library: SchemaServiceConnectionIdempotencyPolicy.

Example

For example, this will override the retry policies for pubsub::Publisher:

  namespace pubsub = ::google::cloud::pubsub;
  using ::google::cloud::future;
  using ::google::cloud::Options;
  using ::google::cloud::StatusOr;
  [](std::string project_id, std::string topic_id) {
    auto topic = pubsub::Topic(std::move(project_id), std::move(topic_id));
    // By default a publisher will retry for 60 seconds, with an initial backoff
    // of 100ms, a maximum backoff of 60 seconds, and the backoff will grow by
    // 30% after each attempt. This changes those defaults.
    auto publisher = pubsub::Publisher(pubsub::MakePublisherConnection(
        std::move(topic),
        Options{}
            .set<pubsub::RetryPolicyOption>(
                pubsub::LimitedTimeRetryPolicy(
                    /*maximum_duration=*/std::chrono::minutes(10))
                    .clone())
            .set<pubsub::BackoffPolicyOption>(
                pubsub::ExponentialBackoffPolicy(
                    /*initial_delay=*/std::chrono::milliseconds(200),
                    /*maximum_delay=*/std::chrono::seconds(45),
                    /*scaling=*/2.0)
                    .clone())));

    std::vector<future<bool>> done;
    for (char const* data : {"1", "2", "3", "go!"}) {
      done.push_back(
          publisher.Publish(pubsub::MessageBuilder().SetData(data).Build())
              .then([](future<StatusOr<std::string>> f) {
                return f.get().ok();
              }));
    }
    publisher.Flush();
    int count = 0;
    for (auto& f : done) {
      if (f.get()) ++count;
    }
    std::cout << count << " messages sent successfully\n";
  }

While this will override the retry policies for pubusb::Subscriber:

  namespace pubsub = ::google::cloud::pubsub;
  using ::google::cloud::future;
  using ::google::cloud::Options;
  using ::google::cloud::StatusOr;
  auto sample = [](std::string project_id, std::string subscription_id) {
    // By default a subscriber will retry for 60 seconds, with an initial
    // backoff of 100ms, a maximum backoff of 60 seconds, and the backoff will
    // grow by 30% after each attempt. This changes those defaults.
    auto subscriber = pubsub::Subscriber(pubsub::MakeSubscriberConnection(
        pubsub::Subscription(std::move(project_id), std::move(subscription_id)),
        Options{}
            .set<pubsub::RetryPolicyOption>(
                pubsub::LimitedTimeRetryPolicy(
                    /*maximum_duration=*/std::chrono::minutes(1))
                    .clone())
            .set<pubsub::BackoffPolicyOption>(
                pubsub::ExponentialBackoffPolicy(
                    /*initial_delay=*/std::chrono::milliseconds(200),
                    /*maximum_delay=*/std::chrono::seconds(10),
                    /*scaling=*/2.0)
                    .clone())));

    auto session = subscriber.Subscribe(
        [](pubsub::Message const& m, pubsub::AckHandler h) {
          std::move(h).ack();
          std::cout << "Received message " << m << "\n";
          PleaseIgnoreThisSimplifiesTestingTheSamples();
        });
    return std::make_pair(subscriber, std::move(session));
  };

Follow these links to find examples for other classes:

More Information

See Also

google::cloud::Options

See Also

google::cloud::BackoffPolicy

See Also

google::cloud::ExponentialBackoffPolicy