Prueba apps de manera local con el emulador

Para desarrollar y probar tu aplicación de forma local, puedes usar el emulador Pub/Sub, que proporciona la emulación local del servicio de producción de Pub/Sub. Ejecuta el emulador de Pub/Sub con Google Cloud CLI.

Para ejecutar tu aplicación con el emulador, primero debes iniciar el emulador y configurar las variables de entorno. Tu aplicación debe comunicarse con el emulador en lugar del servicio de producción de Pub/Sub. Los recursos creados y los mensajes publicados en el emulador se mantienen durante la vida útil de la sesión del emulador.

Antes de comenzar

Completa los siguientes requisitos previos antes de usar el emulador de Pub/Sub:

Instala el emulador

Instala el emulador desde un símbolo del sistema:

gcloud components install pubsub-emulator
gcloud components update

Instala el emulador como una imagen de contenedor

Para instalar y ejecutar el emulador como contenedor, descarga e instala la imagen de Docker de gCloud.

Inicia el emulador

Para iniciar el emulador, invoca pubsub start desde un símbolo del sistema. Antes de ejecutar el comando, reemplaza PUBSUB_PROJECT_ID por una string válida del ID del proyecto de Google Cloud. No es necesario que la cadena represente un proyecto de Google Cloud real porque el emulador de Pub/Sub se ejecuta de forma local.

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

Consulta gcloud beta emulators pubsub start para obtener una lista completa de marcas.

Después de iniciar el emulador, verás un mensaje similar al siguiente:

...
[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

Este mensaje indica que el servidor de Pub/Sub se está ejecutando en el extremo del emulador en tu máquina local y no en el extremo de Google Cloud. Todas las operaciones ocurren de forma local, incluidas las siguientes:

  • La creación de un tema o una suscripción
  • La publicación
  • La suscripción

Configura variables de entorno

Una vez que hayas iniciado el emulador, debes establecer las variables de entorno para que tu aplicación se conecte al emulador y no a Pub/Sub. Configura estas variables de entorno en la misma máquina que usas para ejecutar tu aplicación.

Debes configurar las variables de entorno cada vez que inicias el emulador. Las variables de entorno dependen de los números de puerto asignados de forma dinámica, que pueden cambiar cuando reinicias el emulador.

Configura las variables de forma automática

Si tu aplicación y el emulador se ejecutan en la misma máquina, puedes configurar las variables del entorno de forma automática:

Linux/macOS

Ejecuta env-init con la sustitución de comandos:

$(gcloud beta emulators pubsub env-init)

Windows

Crea y ejecuta un archivo por lotes con el resultado de env-init:

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

Ahora tu aplicación se conectará al emulador de Pub/Sub.

Configura las variables de forma manual

Si tu aplicación y el emulador se ejecutan en máquinas diferentes, configura las variables de entorno de forma manual:

  1. Ejecuta el comando env-init:

     gcloud beta emulators pubsub env-init

  2. En la máquina que ejecuta la aplicación, establece el valor y la variable de entorno PUBSUB_EMULATOR_HOST como se indica en el resultado del comando env-init. Esta configuración conecta tu aplicación al emulador. También tienes la opción de configurar la variable de entorno PUBSUB_PROJECT_ID en el proyecto que deseas usar para el emulador.

    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

Ahora tu aplicación se conectará al emulador de Pub/Sub.

Nota: Si usas el servidor de desarrollo local del entorno estándar de App Engine para Python, debes pasar esta variable de entorno en la línea de comandos de la siguiente manera:

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

dev_appserver.py se incluye en tu [PATH_TO_CLOUD_SDK]/google-cloud-sdk/bin/dev_appserver.py.

Usa el emulador

Para usar el emulador, debes tener una aplicación compilada con las bibliotecas cliente de Cloud. El emulador no es compatible con la consola de Google Cloud ni con los comandos gcloud pubsub.

En el siguiente ejemplo, se muestra cómo usar el emulador y una aplicación que usa la biblioteca cliente de Cloud para Python para realizar varias operaciones. Algunos ejemplos de estas operaciones son cómo crear un tema, publicar mensajes y leerlos.

Completa los siguientes pasos en la máquina en la que configuraste las variables de entorno del emulador:

  1. Obtén los ejemplos de Pub/Sub para Python desde GitHub mediante la clonación del repositorio completo de Python.

  2. En el repositorio clonado, navega hacia el directorio samples/snippets. Completa el resto de estos pasos en este directorio.

  3. Desde el directorio samples/snippets, instala las dependencias que necesitas para ejecutar el ejemplo:

    pip install -r requirements.txt
    
  4. Crea un tema:

     python publisher.py PUBSUB_PROJECT_ID create TOPIC_ID
    
  5. Si no tienes un extremo de envío local con el que probar las suscripciones de envío en el emulador, completa los siguientes pasos para crear uno en http://[::1]:3000/messages (opcional).

    1. Instala el servidor JSON.
      npm install -g json-server
      
    2. Inicia el servidor JSON.
      json-server --port 3000 --watch db.json
      
      En el ejemplo anterior, db.json contiene el siguiente código de partida:
      {
         "messages": []
      }
      
    3. Anota http://[::1]:3000/messages para PUSH_ENDPOINT en el siguiente paso.
  6. Crea una suscripción al tema:

    • Crea una suscripción de extracción:

      python subscriber.py PUBSUB_PROJECT_ID create TOPIC_ID SUBSCRIPTION_ID
      
    • Crea una suscripción de envío:

      python subscriber.py PUBSUB_PROJECT_ID create-push TOPIC_ID SUBSCRIPTION_ID \
      PUSH_ENDPOINT
      
  7. Publica mensajes en el tema:

     python publisher.py PUBSUB_PROJECT_ID publish TOPIC_ID
    
  8. Lee los mensajes publicados en el tema:

    • Recupera mensajes de tu suscripción de extracción:

      python subscriber.py PUBSUB_PROJECT_ID receive SUBSCRIPTION_ID
      
    • Observa cómo se entregan los mensajes a tu extremo de envío local. Por ejemplo, los mensajes son similar a lo siguiente:

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

Accede a variables de entorno

En todos los lenguajes, excepto Java y C#, si configuraste PUBSUB_EMULATOR_HOST como se describe en la sección Configura variables de entorno, las bibliotecas cliente de Pub/Sub llaman a la API que se ejecuta en la instancia local de forma automática, y no a Pub/Sub.

Sin embargo, con las bibliotecas cliente de C# y Java, se requiere que modifiques el código para usar el emulador:

C#

Antes de probar esta muestra, sigue las instrucciones de configuración de C# que encontrarás en la guía de inicio rápido de Pub/Sub con bibliotecas cliente. Si quieres obtener más información, consulta la documentación de referencia de la API de C# de Pub/Sub.

Para autenticarte en Pub/Sub, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para un entorno de desarrollo 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 probar esta muestra, sigue las instrucciones de configuración de Java que encontrarás en la guía de inicio rápido de Pub/Sub con bibliotecas cliente. Si quieres obtener más información, consulta la documentación de referencia de la API de Java de Pub/Sub.

Para autenticarte en Pub/Sub, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para un entorno de desarrollo local.


import com.google.api.core.ApiFuture;
import com.google.api.gax.core.CredentialsProvider;
import com.google.api.gax.core.NoCredentialsProvider;
import com.google.api.gax.grpc.GrpcTransportChannel;
import com.google.api.gax.rpc.FixedTransportChannelProvider;
import com.google.api.gax.rpc.TransportChannelProvider;
import com.google.cloud.pubsub.v1.Publisher;
import com.google.cloud.pubsub.v1.TopicAdminClient;
import com.google.cloud.pubsub.v1.TopicAdminSettings;
import com.google.protobuf.ByteString;
import com.google.pubsub.v1.PubsubMessage;
import com.google.pubsub.v1.Topic;
import com.google.pubsub.v1.TopicName;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;

public class UsePubSubEmulatorExample {
  public static void main(String... args) throws Exception {
    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`.
      // Can be done similarly for a `SubscriptionAdminClient`.
      TopicAdminClient topicAdminClient =
          TopicAdminClient.create(
              TopicAdminSettings.newBuilder()
                  .setTransportChannelProvider(channelProvider)
                  .setCredentialsProvider(credentialsProvider)
                  .build());

      TopicName topicName = TopicName.of("my-project-id", "my-topic-id");
      Topic topic = topicAdminClient.createTopic(topicName);
      System.out.println("Created topic: " + topic.getName());

      // Set the channel and credentials provider when creating a `Publisher`.
      // Can be done similarly for a `Subscriber`.
      Publisher publisher =
          Publisher.newBuilder(topicName)
              .setChannelProvider(channelProvider)
              .setCredentialsProvider(credentialsProvider)
              .build();

      String message = "Hello World!";
      ByteString data = ByteString.copyFromUtf8(message);
      PubsubMessage pubsubMessage = PubsubMessage.newBuilder().setData(data).build();

      ApiFuture<String> messageIdFuture = publisher.publish(pubsubMessage);
      String messageId = messageIdFuture.get();
      System.out.println("Published message ID: " + messageId);
    } finally {
      channel.shutdown();
    }
  }
}

Detén el emulador

Para detener el emulador, presiona Control + C.

Una vez que el emulador esté detenido, ejecuta el siguiente comando con el fin de quitar la variable de entorno PUBSUB_EMULATOR_HOST para que la aplicación se conecte a Pub/Sub:

Linux/macOS
unset PUBSUB_EMULATOR_HOST
Windows
set PUBSUB_EMULATOR_HOST=

Argumentos de línea de comandos del emulador

Para obtener detalles sobre los argumentos de la línea de comandos del emulador de Pub/Sub, consulta gcloud beta emulators pubsub.

Funciones admitidas

El emulador admite las siguientes funciones de Pub/Sub:

  • Publica mensajes
  • Recibe mensajes de suscripciones de envío y de extracción
  • Ordena mensajes
  • Volver a reproducir mensajes
  • Reenvío de mensajes a temas de mensajes no entregados
  • Políticas de reintentos en la entrega de mensajes
  • Compatibilidad con esquemas para Avro

Limitaciones conocidas

  • No se admiten las RPC de UpdateTopic y UpdateSnapshot.
  • No se admiten operaciones de IAM.
  • No se admite la retención de mensajes configurable; todos los mensajes se retienen por tiempo indefinido.
  • No se admite la expiración de suscripciones. Las suscripciones no vencen.
  • No se admite el filtrado.
  • Compatibilidad con esquemas para búferes de protocolo
  • Se pueden crear suscripciones a BigQuery, pero no envían mensajes a BigQuery.
  • No se admite la búsqueda de una marca de tiempo para las suscripciones ordenadas.

Para informar problemas, envía un registro público de problemas.

¿Qué sigue?

  • Para obtener más información sobre cómo usar el emulador de Pub/Sub con minikube, consulta esta entrada de blog.