Voltar a tentar pedidos

Normalmente, as falhas de publicação são causadas por gargalos do lado do cliente, como CPUs de serviço insuficientes, estado de funcionamento dos threads deficiente ou congestionamento da rede. A política de novas tentativas do publicador define o número de vezes que o Pub/Sub tenta entregar uma mensagem e o período entre cada tentativa.

Este documento fornece informações sobre a utilização de pedidos de repetição com mensagens publicadas num tópico.

Antes de começar

Antes de configurar o fluxo de trabalho de publicação, certifique-se de que concluiu as seguintes tarefas:

Funções necessárias

Para receber as autorizações de que precisa para repetir os pedidos de mensagens para um tópico, peça ao seu administrador para lhe conceder a função do IAM de publicador do Pub/Sub (roles/pubsub.publisher) no tópico. Para mais informações sobre a atribuição de funções, consulte o artigo Faça a gestão do acesso a projetos, pastas e organizações.

Também pode conseguir as autorizações necessárias através de funções personalizadas ou outras funções predefinidas.

Precisa de autorizações adicionais para criar ou atualizar tópicos e subscrições.

Acerca dos pedidos de repetição

As definições de repetição controlam a forma como as bibliotecas de cliente do Pub/Sub repetem os pedidos de publicação. As bibliotecas de cliente têm qualquer uma das seguintes definições de repetição:

  • Limite de tempo da solicitação inicial: o tempo antes de uma biblioteca do cliente deixar de aguardar a conclusão da solicitação de publicação inicial.
  • Atraso na nova tentativa: o tempo após o limite de tempo de um pedido que uma biblioteca do cliente aguarda para repetir o pedido.
  • Tempo limite total: o tempo após o qual uma biblioteca cliente deixa de tentar novamente os pedidos de publicação.

Para repetir os pedidos de publicação, o limite de tempo inicial do pedido tem de ser inferior ao limite de tempo total. Por exemplo, se estiver a usar o recuo exponencial, as bibliotecas cliente calculam o tempo limite do pedido e o atraso na nova tentativa da seguinte forma:

  • Após cada pedido de publicação, o limite de tempo do pedido aumenta pelo multiplicador do limite de tempo do pedido, até ao limite de tempo do pedido máximo.
  • Após cada nova tentativa, o atraso da nova tentativa aumenta pelo multiplicador do atraso da nova tentativa, até ao atraso máximo da nova tentativa.

Tente novamente um pedido de mensagem

Durante o processo de publicação, pode ver falhas de publicação transitórias ou permanentes. Normalmente, não tem de tomar nenhuma ação especial para erros transitórios, uma vez que o Pub/Sub tenta novamente as mensagens automaticamente.

Também pode ocorrer um erro quando uma operação de publicação é bem-sucedida, mas o cliente do publicador não recebe a resposta de publicação a tempo. Também neste caso, a operação de publicação é repetida. Como resultado, pode ter duas mensagens idênticas com IDs de mensagens diferentes.

Em caso de erros persistentes, considere implementar ações adequadas fora do processo de publicação para evitar sobrecarregar o Pub/Sub.

As falhas de publicação são repetidas automaticamente, exceto no caso de erros que não justificam repetições. Este exemplo de código demonstra a criação de um publicador com definições de repetição personalizadas (tenha em atenção que nem todas as bibliotecas cliente suportam definições de repetição personalizadas; consulte a documentação de referência da API para o idioma escolhido):

C++

Antes de experimentar este exemplo, siga as instruções de configuração do C++ no artigo Início rápido: usar bibliotecas de cliente. Para mais informações, consulte a documentação de referência da API C++ do Pub/Sub.

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

C#

Antes de experimentar este exemplo, siga as instruções de configuração do C# no artigo Início rápido: usar bibliotecas de cliente. Para mais informações, consulte a documentação de referência da API C# do Pub/Sub.


using Google.Api.Gax.Grpc;
using Google.Cloud.PubSub.V1;
using Grpc.Core;
using System;
using System.Threading.Tasks;

public class PublishMessageWithRetrySettingsAsyncSample
{
    public async Task PublishMessageWithRetrySettingsAsync(string projectId, string topicId, string messageText)
    {
        TopicName topicName = TopicName.FromProjectTopic(projectId, topicId);
        // Retry settings control how the publisher handles retry-able failures
        var maxAttempts = 3;
        var initialBackoff = TimeSpan.FromMilliseconds(110); // default: 100 ms
        var maxBackoff = TimeSpan.FromSeconds(70); // default : 60 seconds
        var backoffMultiplier = 1.3; // default: 1.0
        var totalTimeout = TimeSpan.FromSeconds(100); // default: 600 seconds

        var publisher = await new PublisherClientBuilder
        {
            TopicName = topicName,
            ApiSettings = new PublisherServiceApiSettings
            {
                PublishSettings = CallSettings.FromRetry(RetrySettings.FromExponentialBackoff(
                               maxAttempts: maxAttempts,
                               initialBackoff: initialBackoff,
                               maxBackoff: maxBackoff,
                               backoffMultiplier: backoffMultiplier,
                               retryFilter: RetrySettings.FilterForStatusCodes(StatusCode.Unavailable)))
                       .WithTimeout(totalTimeout)
            }
        }.BuildAsync();
        string message = await publisher.PublishAsync(messageText);
        Console.WriteLine($"Published message {message}");
        // PublisherClient instance should be shutdown after use.
        // The TimeSpan specifies for how long to attempt to publish locally queued messages.
        await publisher.