Como testar aplicativos localmente com o emulador

Para desenvolver e testar seu aplicativo localmente, é possível usar o emulador do Pub/Sub, que fornece emulação local do serviço de produção do Pub/Sub. Execute o emulador do Pub/Sub usando a Google Cloud CLI.

Para executar seu aplicativo no emulador, primeiro inicie o emulador e defina as variáveis de ambiente. Seu aplicativo precisa se comunicar com o emulador em vez do serviço de produção Pub/Sub. Os recursos criados e as mensagens publicadas no emulador são mantidos durante a vida útil da sessão dele.

Antes de começar

Conclua os seguintes pré-requisitos antes de usar o emulador do Pub/Sub:

Instalar o emulador

Instale o emulador no prompt de comando:

gcloud components install pubsub-emulator
gcloud components update

Instalar o emulador como uma imagem de contêiner

Para instalar e executar o emulador como um contêiner, faça o download e instale a imagem Docker do gcloud.

Iniciar o emulador

Invoque pubsub start em um prompt de comando para iniciar o emulador. Antes de executar o comando, substitua PUBSUB_PROJECT_ID por uma string válida de ID do projeto do Google Cloud. A string não precisa representar um projeto real do Google Cloud porque o emulador do Pub/Sub é executado localmente.

gcloud beta emulators pubsub start --project=PUBSUB_PROJECT_ID [options]

Consulte gcloud beta emulators pubsub start para ver uma lista completa de sinalizações.

Depois de iniciar o emulador, você verá uma mensagem como esta:

...
[pubsub] This is the Pub/Sub fake.
[pubsub] Implementation may be incomplete or differ from the real system.
...
[pubsub] INFO: Server started, listening on 8085

Essa mensagem indica que o servidor Pub/Sub é executado no endpoint do emulador na sua máquina local em vez de no endpoint do Google Cloud. Todas as operações acontecem localmente, incluindo o seguinte:

  • criação de um tópico ou de uma assinatura;
  • publicação;
  • Inscrição

Definir variáveis de ambiente

Depois de iniciar o emulador, defina as variáveis de ambiente para que o aplicativo se conecte ao emulador em vez do Pub/Sub. Faça isso na mesma máquina usada na execução do seu aplicativo.

Você precisa definir as variáveis de ambiente sempre que iniciar o emulador. Elas dependem de números de portas dinamicamente atribuídas que podem ser alteradas durante a reinicialização do emulador.

Como configurar automaticamente as variáveis

Se o aplicativo e o emulador forem executados na mesma máquina, defina as variáveis de ambiente automaticamente:

Linux/macOS

Execute env-init usando a substituição de comando:

$(gcloud beta emulators pubsub env-init)

Windows

Crie e execute um arquivo de lote usando a saída de env-init:

gcloud beta emulators pubsub env-init > set_vars.cmd && set_vars.cmd

O aplicativo se conectará ao emulador do Pub/Sub.

Como configurar manualmente as variáveis

Se o aplicativo e o emulador forem executados em máquinas diferentes, configure as variáveis de ambiente manualmente:

  1. Execute o comando env-init:

     gcloud beta emulators pubsub env-init

  2. Na máquina que executa o aplicativo, defina o valor e a variável de ambiente PUBSUB_EMULATOR_HOST de acordo com a direção da saída do comando env-init. Essa configuração conecta seu aplicativo ao emulador. Opcionalmente, você pode definir a variável de ambiente PUBSUB_PROJECT_ID para o projeto que quer usar para o emulador. Exemplo:

    Linux / macOS
    export PUBSUB_EMULATOR_HOST=[::1]:8432
    export PUBSUB_PROJECT_ID=my-project-id
    Windows
    set PUBSUB_EMULATOR_HOST=[::1]:8432
    set PUBSUB_PROJECT_ID=my-project-id

O aplicativo se conectará ao emulador do Pub/Sub.

Observação: se você estiver usando o servidor de desenvolvimento local padrão do App Engine para Python, passe essa variável de ambiente na linha de comando da seguinte maneira:

dev_appserver.py app.yaml --env_var PUBSUB_EMULATOR_HOST=${PUBSUB_EMULATOR_HOST}

dev_appserver.py está incluído no seu [PATH_TO_CLOUD_SDK]/google-cloud-sdk/bin/dev_appserver.py.

Como usar o emulador

Para usar o emulador, você precisa ter um aplicativo criado com as bibliotecas de cliente do Cloud. O emulador não oferece suporte ao console do Google Cloud ou aos comandos gcloud pubsub.

O exemplo a seguir demonstra como usar o emulador e um aplicativo que usa a biblioteca de cliente do Cloud para Python para executar várias operações. Exemplos dessas operações incluem como criar um tópico, publicar e ler mensagens.

Conclua as seguintes etapas no computador em que você configurou as variáveis de ambiente do emulador:

  1. Faça o download das amostras do Pub/Sub para Python no GitHub. Para isso, clone o repositório inteiro do Python (em inglês).

  2. Em seu repositório clonado, navegue até o diretório samples/snippets. Conclua o restante das etapas nesse diretório.

  3. No diretório samples/snippets, instale as dependências necessárias para executar o exemplo:

    pip install -r requirements.txt
    
  4. Crie um tópico:

     python publisher.py PUBSUB_PROJECT_ID create TOPIC_ID
    
  5. (Opcional) Se você não tiver um endpoint de push local para testar assinaturas de push no emulador, conclua as etapas a seguir para criar um em http://[::1]:3000/messages.

    1. Instale o servidor JSON.
      npm install -g json-server
      
    2. Inicie o servidor JSON.
      json-server --port 3000 --watch db.json
      
      em que db.json contém o seguinte código inicial:
      {
         "messages": []
      }
      
    3. Anote http://[::1]:3000/messages para PUSH_ENDPOINT na próxima etapa.
  6. Crie uma assinatura para o tópico:

    • Crie uma assinatura de pull:

      python subscriber.py PUBSUB_PROJECT_ID create TOPIC_ID SUBSCRIPTION_ID
      
    • Crie uma inscrição de push:

      python subscriber.py PUBSUB_PROJECT_ID create-push TOPIC_ID SUBSCRIPTION_ID \
      PUSH_ENDPOINT
      
  7. Publique mensagens no tópico:

     python publisher.py PUBSUB_PROJECT_ID publish TOPIC_ID
    
  8. Leia as mensagens publicadas no tópico:

    • Recupere as mensagens da assinatura de pull:

      python subscriber.py PUBSUB_PROJECT_ID receive SUBSCRIPTION_ID
      
    • Observe as mensagens entregues no endpoint de push local. Por exemplo, as mensagens têm esta aparência:

      {
        "messages": [
            {
                "subscription": "projects/PUBSUB_PROJECT_ID/subscriptions/SUBSCRIPTION_ID",
                "message": {
                    "data": "TWVzc2FnZSBudW1iZXIgMQ==",
                    "messageId": "10",
                    "attributes": {}
                },
                "id": 1
            },
            ...
        ]
      }
      

Como acessar as variáveis de ambiente

Em todas as linguagens, exceto Java e C#, se você configurar PUBSUB_EMULATOR_HOST conforme descrito em Como definir variáveis de ambiente, as bibliotecas de cliente do Pub/Sub chamarão automaticamente a API em execução na instância local em vez do Pub/Sub.

No entanto, é preciso modificar seu código para usar o emulador nas bibliotecas cliente C# e Java:

C#

Antes de testar esta amostra, siga as instruções de configuração de C# no Guia de início rápido do Pub/Sub usando bibliotecas de cliente. Para mais informações, consulte a documentação de referência da API Pub/Sub C#.

Para se autenticar no Pub/Sub, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.


using Google.Api.Gax;
using Google.Cloud.PubSub.V1;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

public class EmulatorSupportSample
{
    public async Task WithEmulatorAsync(string projectId, string topicId, string subscriptionId)
    {
        // Use EmulatorDetection.EmulatorOrProduction to create service clients that will
        // that will connect to the PubSub emulator if the PUBSUB_EMULATOR_HOST environment
        // variable is set, but will otherwise connect to the production environment.

        // Create the PublisherServiceApiClient using the PublisherServiceApiClientBuilder
        // and setting the EmulatorDection property.
        PublisherServiceApiClient publisherService = await new PublisherServiceApiClientBuilder
        {
            EmulatorDetection = EmulatorDetection.EmulatorOrProduction
        }.BuildAsync();

        // Use the client as you'd normally do, to create a topic in this example.
        TopicName topicName = new TopicName(projectId, topicId);
        publisherService.CreateTopic(topicName);

        // Create the SubscriberServiceApiClient using the SubscriberServiceApiClientBuilder
        // and setting the EmulatorDection property.
        SubscriberServiceApiClient subscriberService = await new SubscriberServiceApiClientBuilder
        {
            EmulatorDetection = EmulatorDetection.EmulatorOrProduction
        }.BuildAsync();

        // Use the client as you'd normally do, to create a subscription in this example.
        SubscriptionName subscriptionName = new SubscriptionName(projectId, subscriptionId);
        subscriberService.CreateSubscription(subscriptionName, topicName, pushConfig: null, ackDeadlineSeconds: 60);

        // Create the PublisherClient using PublisherClientBuilder to set the EmulatorDetection property.
        PublisherClient publisher = await new PublisherClientBuilder
        {
            TopicName = topicName,
            EmulatorDetection = EmulatorDetection.EmulatorOrProduction
        }.BuildAsync();
        // Use the client as you'd normally do, to send a message in this example.
        await publisher.PublishAsync("Hello, Pubsub");
        await publisher.ShutdownAsync(TimeSpan.FromSeconds(15));

        // Create the SubscriberClient using SubscriberClientBuild to set the EmulatorDetection property.
        SubscriberClient subscriber = await new SubscriberClientBuilder
        {
            SubscriptionName = subscriptionName,
            EmulatorDetection = EmulatorDetection.EmulatorOrProduction
        }.BuildAsync();
        List<PubsubMessage> receivedMessages = new List<PubsubMessage>();

        // Use the client as you'd normally do, to listen for messages in this example.
        await subscriber.StartAsync((msg, cancellationToken) =>
        {
            receivedMessages.Add(msg);
            Console.WriteLine($"Received message {msg.MessageId} published at {msg.PublishTime.ToDateTime()}");
            Console.WriteLine($"Text: '{msg.Data.ToStringUtf8()}'");
            // In this example we stop the subscriber when the message is received.
            // You may leave the subscriber running, and it will continue to received published messages
            // if any.
            // This is non-blocking, and the returned Task may be awaited.
            subscriber.StopAsync(TimeSpan.FromSeconds(15));
            // Return Reply.Ack to indicate this message has been handled.
            return Task.FromResult(SubscriberClient.Reply.Ack);
        });
    }
}

Java

Antes de testar esta amostra, siga as instruções de configuração de Java no Guia de início rápido do Pub/Sub usando bibliotecas de cliente. Para mais informações, consulte a documentação de referência da API Pub/Sub Java.

Para se autenticar no Pub/Sub, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.

String hostport = System.getenv("PUBSUB_EMULATOR_HOST");
ManagedChannel channel = ManagedChannelBuilder.forTarget(hostport).usePlaintext().build();
try {
  TransportChannelProvider channelProvider =
      FixedTransportChannelProvider.create(GrpcTransportChannel.create(channel));
  CredentialsProvider credentialsProvider = NoCredentialsProvider.create();

  // Set the channel and credentials provider when creating a `TopicAdminClient`.
  // Similarly for SubscriptionAdminClient
  TopicAdminClient topicClient =
      TopicAdminClient.create(
          TopicAdminSettings.newBuilder()
              .setTransportChannelProvider(channelProvider)
              .setCredentialsProvider(credentialsProvider)
              .build());

  TopicName topicName = TopicName.of("my-project-id", "my-topic-id");
  // Set the channel and credentials provider when creating a `Publisher`.
  // Similarly for Subscriber
  Publisher publisher =
      Publisher.newBuilder(topicName)
          .setChannelProvider(channelProvider)
          .setCredentialsProvider(credentialsProvider)
          .build();
} finally {
  channel.shutdown();
}

Interromper o emulador

Para interromper o emulador, pressione as teclas Ctrl+C.

Depois de interromper o emulador, execute o seguinte comando para remover a variável de ambiente PUBSUB_EMULATOR_HOST para que o aplicativo se conecte ao Pub/Sub:

Linux / macOS
unset PUBSUB_EMULATOR_HOST
Windows
set PUBSUB_EMULATOR_HOST=

Argumentos de linha de comando do emulador

Consulte os detalhes sobre argumentos de linha de comando do emulador Pub/Sub em gcloud beta emulators pubsub.

Recursos compatíveis

O emulador é compatível com os seguintes recursos do Pub/Sub:

  • Como publicar mensagens
  • Como receber mensagens de assinaturas de push e pull
  • Como ordenar mensagens
  • Como repetir mensagens
  • Como encaminhar mensagens a tópicos de mensagens inativas
  • Políticas de repetição na entrega de mensagens
  • Compatibilidade do esquema para Avro

Limitações conhecidas

  • RPCs UpdateTopic e UpdateSnapshot não são compatíveis.
  • As operações do IAM não são compatíveis.
  • A retenção configurável de mensagens não é compatível. Todas as mensagens são retidas indefinidamente.
  • A expiração da assinatura não é compatível. As assinaturas não expiram.
  • A filtragem não é compatível.
  • Compatibilidade do esquema para buffers de protocolo.
  • É possível criar assinaturas do BigQuery, mas elas não enviam mensagens a ele.
  • Não é possível procurar um carimbo de data/hora para assinaturas ordenadas.

Para registrar problemas, envie um Issue Tracker público.

A seguir

  • Para aprender a usar o emulador do Pub/Sub com o minikube, consulte esta postagem do blog.