Risoluzione dei problemi generali

Scopri i passaggi per la risoluzione dei problemi, utili in caso di problemi nell'utilizzo di Pub/Sub.

Impossibile creare un argomento

Verifica di disporre delle autorizzazioni necessarie. Per creare un argomento Pub/Sub, devi disporre del ruolo Editor Pub/Sub (roles/pubsub.editor) di Identity and Access Management sul progetto. Se non disponi di questo ruolo, contatta l'amministratore. Per ulteriori informazioni sulla risoluzione dei problemi relativi agli argomenti, consulta le seguenti pagine:

Impossibile creare un abbonamento

Verifica di aver svolto le seguenti operazioni:

  • Verifica di disporre delle autorizzazioni necessarie. Per creare una sottoscrizione Pub/Sub, devi disporre del ruolo IAM Editor Pub/Sub (roles/pubsub.editor) per il progetto. Se non disponi di questo ruolo, contatta l'amministratore.

  • Specificato un nome per l'abbonamento.

  • Ha specificato il nome di un argomento esistente a cui vuoi collegare l'abbonamento.

  • Se crei un abbonamento push, specifica https:// in minuscolo (non http:// o HTTPS://) come protocollo per l'URL di ricezione nel campo pushEndpoint.

Per ulteriori informazioni sulla risoluzione dei problemi relativi agli abbonamenti, consulta le seguenti pagine:

Risolvere i problemi relativi alle autorizzazioni

Le autorizzazioni Pub/Sub controllano quali utenti e service account possono eseguire azioni sulle tue risorse Pub/Sub. Quando le autorizzazioni sono configurate in modo errato, possono verificarsi errori di autorizzazione negata e interrompere il flusso dei messaggi. I log di controllo forniscono un registro dettagliato di tutte le modifiche alle autorizzazioni, consentendoti di identificare l'origine di questi problemi.

Per risolvere i problemi di autorizzazione Pub/Sub con i log di controllo:

  1. Ottieni le autorizzazioni necessarie per visualizzare Esplora log.

    Per ulteriori informazioni, consulta la sezione Prima di iniziare.

  2. Nella console Google Cloud , vai alla pagina Esplora log.

    Vai a Esplora log

  3. Seleziona un progetto, una cartella o un'organizzazione Google Cloud esistente.

  4. Di seguito è riportato un elenco di filtri che puoi utilizzare per trovare i log pertinenti:

    • resource.type="pubsub_topic" OR resource.type="pubsub_subscription": Utilizza questa query come punto di partenza per la risoluzione dei problemi che potrebbero comportare modifiche alle configurazioni di argomenti o abbonamenti o al controllo dell'accesso. Puoi combinarlo con altri filtri per perfezionare ulteriormente la ricerca.

    • protoPayload.methodName="google.iam.v1.SetIamPolicy": utilizza questa query quando sospetti che un problema sia causato da autorizzazioni errate o mancanti. Ti aiuta a tenere traccia di chi ha apportato modifiche al criterio IAM e quali sono state queste modifiche. Questo può essere utile per risolvere problemi come utenti che non riescono a pubblicare argomenti o abbonarsi a sottoscrizioni, applicazioni a cui è stato negato l'accesso alle risorse Pub/Sub o modifiche impreviste controllo dell'accessollo dell'accesso.

    • protoPayload.status.code=7: utilizza questa query quando si verificano errori esplicitamente correlati alle autorizzazioni. In questo modo puoi individuare le azioni che non vanno a buon fine e chi le sta tentando. Puoi combinare questa query con quelle precedenti per identificare la risorsa specifica e la modifica del criterio IAM che potrebbe causare il rifiuto dell'autorizzazione.

  5. Analizza i log per determinare fattori quali il timestamp dell'evento, il principal che ha apportato la modifica e il tipo di modifiche apportate.

  6. In base alle informazioni raccolte dai log di controllo, puoi intraprendere azioni correttive.

L'abbonamento è stato eliminato

Le sottoscrizioni Pub/Sub possono essere eliminate in due modi principali:

  • Un utente o un account di servizio con autorizzazioni sufficienti elimina intenzionalmente l'abbonamento.

  • Un abbonamento viene eliminato automaticamente dopo un periodo di inattività, che per impostazione predefinita è di 31 giorni. Per ulteriori informazioni sulle norme relative alla scadenza dell'abbonamento, consulta Periodo di scadenza.

Per risolvere i problemi relativi a un abbonamento eliminato, segui questi passaggi:

  1. Nella console Google Cloud , vai alla pagina Sottoscrizioni Pub/Sub e verifica che la sottoscrizione non sia più elencata. Per maggiori informazioni su come elencare gli abbonamenti, vedi Elencare un abbonamento.

  2. Controlla i log di controllo. Vai a Esplora log. Utilizza il filtro protoPayload.methodName="google.pubsub.v1.Subscriber.DeleteSubscription" per trovare gli abbonamenti eliminati. Esamina i log per determinare se qualcuno ha eliminato l'abbonamento o se è stato eliminato a causa dell'inattività. InternalExpireInactiveSubscription indica che un abbonamento è stato eliminato per inattività. Per ulteriori informazioni su come utilizzare i log di controllo per la risoluzione dei problemi, vedi Risolvere i problemi di Pub/Sub con i log di controllo.

403 (Forbidden) errore

Un errore 403 in genere indica che non disponi delle autorizzazioni corrette per eseguire un'azione. Ad esempio, potresti ricevere un errore 403 User not authorized quando provi a pubblicare in un argomento o a eseguire il pull da un abbonamento.

Se ricevi questo errore, procedi nel seguente modo:

  • Assicurati di aver abilitato l'API Pub/Sub nella consoleGoogle Cloud .
  • Assicurati che l'entità che effettua la richiesta disponga delle autorizzazioni richieste per le risorse API Pub/Sub pertinenti, soprattutto se utilizzi l'API Pub/Sub per la comunicazione tra progetti.

  • Se utilizzi Dataflow, assicurati che sia {PROJECT_NUMBER}@cloudservices.gserviceaccount.com sia il service account Compute Engine {PROJECT_NUMBER}-compute@developer.gserviceaccount.com dispongano delle autorizzazioni richieste per la risorsa API Pub/Sub pertinente. Per ulteriori informazioni, vedi Sicurezza e autorizzazioni di Dataflow.

  • Se utilizzi App Engine, controlla la pagina Autorizzazioni del progetto per vedere se un account di servizio App Engine è elencato come editor Pub/Sub. In caso contrario, aggiungi il service account App Engine come editor Pub/Sub. Normalmente, il service account App Engine è del modulo <project-id>@appspot.gserviceaccount.com.

  • Puoi utilizzare i log di controllo per risolvere i problemi di autorizzazione.

Altri codici di errore comuni

Per un elenco di altri codici di errore comuni relativi all'API Pub/Sub e alle relative descrizioni, consulta Codici di errore.

Utilizzo di quantità eccessive di operazioni amministrative

Se noti di utilizzare una parte troppo grande della tua quota per le operazioni amministrative, potresti dover eseguire il refactoring del codice. Ad esempio, considera questo pseudocodice. In questo esempio, un'operazione amministrativa (GET) viene utilizzata per verificare la presenza di un abbonamento prima che tenti di utilizzare le sue risorse. GET e CREATE sono operazioni amministrative:

if !GetSubscription my-sub {
  CreateSubscription my-sub
}
Consume from subscription my-sub

Un pattern più efficiente consiste nel tentare di utilizzare i messaggi dell'abbonamento (supponendo che tu possa essere ragionevolmente certo del nome dell'abbonamento). In questo approccio ottimistico, l'abbonamento viene creato o recuperato solo se si verifica un errore. Considera questo esempio:

try {
  Consume from subscription my-sub
} catch NotFoundError {
  CreateSubscription my-sub
  Consume from subscription my-sub
}

Puoi utilizzare i seguenti esempi di codice per implementare questo pattern nel linguaggio che preferisci:

Vai

L'esempio seguente utilizza la versione principale della libreria client Go Pub/Sub (v2). Se utilizzi ancora la libreria v1, consulta la guida alla migrazione alla v2. Per visualizzare un elenco di esempi di codice della versione 1, consulta gli esempi di codice ritirati.

Prima di provare questo esempio, segui le istruzioni di configurazione di Go nella guida rapida all'utilizzo delle librerie client. Per saperne di più, consulta la documentazione di riferimento dell'API Pub/Sub Go.

import (
	"context"
	"errors"
	"fmt"
	"io"
	"time"

	"cloud.google.com/go/pubsub/v2"
	"cloud.google.com/go/pubsub/v2/apiv1/pubsubpb"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

// optimisticSubscribe shows the recommended pattern for optimistically
// assuming a subscription exists prior to receiving messages.
func optimisticSubscribe(w io.Writer, projectID, topic, subscriptionName string) error {
	// projectID := "my-project-id"
	// topic := "projects/my-project-id/topics/my-topic"
	// subscription := "projects/my-project/subscriptions/my-sub"
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("pubsub.NewClient: %w", err)
	}
	defer client.Close()

	// client.Subscriber can be passed a subscription ID (e.g. "my-sub") or
	// a fully qualified name (e.g. "projects/my-project/subscriptions/my-sub").
	// If a subscription ID is provided, the project ID from the client is used.
	sub := client.Subscriber(subscriptionName)

	// Receive messages for 10 seconds, which simplifies testing.
	// Comment this out in production, since `Receive` should
	// be used as a long running operation.
	ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
	defer cancel()

	// Instead of checking if the subscription exists, optimistically try to
	// receive from the subscription assuming it exists.
	err = sub.Receive(ctx, func(_ context.Context, msg *pubsub.Message) {
		fmt.Fprintf(w, "Got from existing subscription: %q\n", string(msg.Data))
		msg.Ack()
	})
	if err != nil {
		if st, ok := status.FromError(err); ok {
			if st.Code() == codes.NotFound {
				// If the subscription does not exist, then create the subscription.
				subscription, err := client.SubscriptionAdminClient.CreateSubscription(ctx, &pubsubpb.Subscription{
					Name:  subscriptionName,
					Topic: topic,
				})
				if err != nil {
					return err
				}
				fmt.Fprintf(w, "Created subscription: %q\n", subscriptionName)

				// client.Subscriber can be passed a subscription ID (e.g. "my-sub") or
				// a fully qualified name (e.g. "projects/my-project/subscriptions/my-sub").
				// If a subscription ID is provided, the project ID from the client is used.
				sub = client.Subscriber(subscription.GetName())
				err = sub.Receive(ctx, func(ctx context.Context, msg *pubsub.Message) {
					fmt.Fprintf(w, "Got from new subscription: %q\n", string(msg.Data))
					msg.Ack()
				})
				if err != nil && !errors.Is(err, context.Canceled) {
					return err
				}
			}
		}
	}
	return nil
}

Java

Prima di provare questo esempio, segui le istruzioni di configurazione di Java nella Guida rapida all'utilizzo delle librerie client. Per ulteriori informazioni, consulta la documentazione di riferimento dell'API Java di Pub/Sub.


import com.google.api.gax.rpc.NotFoundException;
import com.google.cloud.pubsub.v1.AckReplyConsumer;
import com.google.cloud.pubsub.v1.MessageReceiver;
import com.google.cloud.pubsub.v1.Subscriber;
import com.google.cloud.pubsub.v1.SubscriptionAdminClient;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.pubsub.v1.ProjectSubscriptionName;
import com.google.pubsub.v1.PubsubMessage;
import com.google.pubsub.v1.PushConfig;
import com.google.pubsub.v1.Subscription;
import com.google.pubsub.v1.TopicName;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class OptimisticSubscribeExample {
  public static void main(String... args) throws Exception {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "your-project-id";
    String subscriptionId = "your-subscription-id";
    String topicId = "your-topic-id";

    optimisticSubscribeExample(projectId, subscriptionId, topicId);
  }

  public static void optimisticSubscribeExample(
      String projectId, String subscriptionId, String topicId) throws IOException {
    ProjectSubscriptionName subscriptionName =
        ProjectSubscriptionName.of(projectId, subscriptionId);

    // Instantiate an asynchronous message receiver.
    MessageReceiver receiver =
        (PubsubMessage message, AckReplyConsumer consumer) -> {
          // Handle incoming message, then ack the received message.
          System.out.println("Id: " + message.getMessageId());
          System.out.println("Data: " + message.getData().toStringUtf8());
          consumer.ack();
        };

    Subscriber subscriber = null;
    try {
      subscriber = Subscriber.newBuilder(subscriptionName, receiver).build();

      // Listen for resource NOT_FOUND errors and rebuild the  subscriber and restart subscribing
      // when the current subscriber encounters these errors.
      subscriber.addListener(
          new Subscriber.Listener() {
            public void failed(Subscriber.State from, Throwable failure) {
              System.out.println(failure.getStackTrace());
              if (failure instanceof NotFoundException) {
                try (SubscriptionAdminClient subscriptionAdminClient =
                    SubscriptionAdminClient.create()) {
                  TopicName topicName = TopicName.of(projectId, topicId);
                  // Create a pull subscription with default acknowledgement deadline of 10 seconds.
                  // The client library will automatically extend acknowledgement deadlines.
                  Subscription subscription =
                      subscriptionAdminClient.createSubscription(
                          subscriptionName, topicName, PushConfig.getDefaultInstance(), 10);
                  System.out.println("Created pull subscription: " + subscription.getName());
                  optimisticSubscribeExample(projectId, subscriptionId, topicId);
                } catch (IOException err) {
                  System.out.println("Failed to create pull subscription: " + err.getMessage());
                }
              }
            }
          },
          MoreExecutors.directExecutor());

      subscriber.startAsync().awaitRunning();
      System.out.printf("Listening for messages on %s:\n", subscriptionName.toString());
      subscriber.awaitTerminated(30, TimeUnit.SECONDS);
    } catch (IllegalStateException e) {
      // Prevent an exception from being thrown if it is the expected NotFoundException
      if (!(subscriber.failureCause() instanceof NotFoundException)) {
        throw e;
      }
    } catch (TimeoutException e) {
      subscriber.stopAsync();
    }
  }
}

Node.js

Prima di provare questo esempio, segui le istruzioni di configurazione di Node.js nella Guida rapida all'utilizzo delle librerie client. Per saperne di più, consulta la documentazione di riferimento dell'API Pub/Sub Node.js.

/**
 * TODO(developer): Uncomment these variables before running the sample.
 */
// const subscriptionNameOrId = 'YOUR_SUBSCRIPTION_NAME_OR_ID';
// const topicNameOrId = 'YOUR_TOPIC_NAME_OR_ID';
// const timeout = 60;

// Imports the Google Cloud client library
const {PubSub} = require('@google-cloud/pubsub');

// Creates a client; cache this for further use
const pubSubClient = new PubSub();

function optimisticSubscribe(subscriptionNameOrId, topicNameOrId, timeout) {
  // Try using an existing subscription
  let subscription = pubSubClient.subscription(subscriptionNameOrId);

  // Create an event handler to handle messages
  let messageCount = 0;
  const messageHandler = message => {
    console.log(`Received message ${message.id}:`);
    console.log(`\tData: ${message.data}`);
    console.log(`\tAttributes: ${message.attributes}`);
    messageCount += 1;

    // "Ack" (acknowledge receipt of) the message
    message.ack();
  };

  // Set an error handler so that we're notified if the subscription doesn't
  // already exist.
  subscription.on('error', async e => {
    // Resource Not Found
    if (e.code === 5) {
      console.log('Subscription not found, creating it');
      await pubSubClient.createSubscription(
        topicNameOrId,
        subscriptionNameOrId,
      );

      // Refresh our subscriber object and re-attach the message handler.
      subscription = pubSubClient.subscription(subscriptionNameOrId);
      subscription.on('message', messageHandler);
    }
  });

  // Listen for new messages until timeout is hit; this will attempt to
  // open the actual subscriber streams. If it fails, the error handler
  // above will be called.
  subscription.on('message', messageHandler);

  // Wait a while for the subscription to run. (Part of the sample only.)
  setTimeout(() => {
    subscription.removeListener('message', messageHandler);
    console.log(`${messageCount} message(s) received.`);
  }, timeout * 1000);
}

Node.ts

Prima di provare questo esempio, segui le istruzioni di configurazione di Node.js nella Guida rapida all'utilizzo delle librerie client. Per saperne di più, consulta la documentazione di riferimento dell'API Pub/Sub Node.js.

/**
 * TODO(developer): Uncomment these variables before running the sample.
 */
// const subscriptionNameOrId = 'YOUR_SUBSCRIPTION_NAME_OR_ID';
// const topicNameOrId = 'YOUR_TOPIC_NAME_OR_ID';
// const timeout = 60;

// Imports the Google Cloud client library
import {PubSub, Message, StatusError} from '@google-cloud/pubsub';

// Creates a client; cache this for further use
const pubSubClient = new PubSub();

function optimisticSubscribe(
  subscriptionNameOrId: string,
  topicNameOrId: string,
  timeout: number,
) {
  // Try using an existing subscription
  let subscription = pubSubClient.subscription(subscriptionNameOrId);

  // Create an event handler to handle messages
  let messageCount = 0;
  const messageHandler = (message: Message) => {
    console.log(`Received message ${message.id}:`);
    console.log(`\tData: ${message.data}`);
    console.log(`\tAttributes: ${message.attributes}`);
    messageCount += 1;

    // "Ack" (acknowledge receipt of) the message
    message.ack();
  };

  // Set an error handler so that we're notified if the subscription doesn't
  // already exist.
  subscription.on('error', async (e: StatusError) => {
    // Resource Not Found
    if (e.code === 5) {
      console.log('Subscription not found, creating it');
      await pubSubClient.createSubscription(
        topicNameOrId,
        subscriptionNameOrId,
      );

      // Refresh our subscriber object and re-attach the message handler.
      subscription = pubSubClient.subscription(subscriptionNameOrId);
      subscription.on('message', messageHandler);
    }
  });

  // Listen for new messages until timeout is hit; this will attempt to
  // open the actual subscriber streams. If it fails, the error handler
  // above will be called.
  subscription.on('message', messageHandler);

  // Wait a while for the subscription to run. (Part of the sample only.)
  setTimeout(() => {
    subscription.removeListener('message', messageHandler);
    console.log(`${messageCount} message(s) received.`);
  }, timeout * 1000);
}

Python

Prima di provare questo esempio, segui le istruzioni di configurazione di Python nella guida rapida all'utilizzo delle librerie client. Per saperne di più, consulta la documentazione di riferimento dell'API Pub/Sub Python.

from google.api_core.exceptions import NotFound
from google.cloud import pubsub_v1
from concurrent.futures import TimeoutError

# TODO(developer)
# project_id = "your-project-id"
# subscription_id = "your-subscription-id"
# Number of seconds the subscriber should listen for messages
# timeout = 5.0
# topic_id = "your-topic-id"

# Create a subscriber client.
subscriber = pubsub_v1.SubscriberClient()

# The `subscription_path` method creates a fully qualified identifier
# in the form `projects/{project_id}/subscriptions/{subscription_id}`
subscription_path = subscriber.subscription_path(project_id, subscription_id)

# Define callback to be called when a message is received.
def callback(message: pubsub_v1.subscriber.message.Message) -> None:
    # Ack message after processing it.
    message.ack()

# Wrap subscriber in a 'with' block to automatically call close() when done.
with subscriber:
    try:
        # Optimistically subscribe to messages on the subscription.
        streaming_pull_future = subscriber.subscribe(
            subscription_path, callback=callback
        )
        streaming_pull_future.result(timeout=timeout)
    except TimeoutError:
        print("Successfully subscribed until the timeout passed.")
        streaming_pull_future.cancel()  # Trigger the shutdown.
        streaming_pull_future.result()  # Block until the shutdown is complete.
    except NotFound:
        print(f"Subscription {subscription_path} not found, creating it.")

        try:
            # If the subscription does not exist, then create it.
            publisher = pubsub_v1.PublisherClient()
            topic_path = publisher.topic_path(project_id, topic_id)
            subscription = subscriber.create_subscription(
                request={"name": subscription_path, "topic": topic_path}
            )

            if subscription:
                print(f"Subscription {subscription.name} created")
            else:
                raise ValueError("Subscription creation failed.")

            # Subscribe on the created subscription.
            try:
                streaming_pull_future = subscriber.subscribe(
                    subscription.name, callback=callback
                )
                streaming_pull_future.result(timeout=timeout)
            except TimeoutError:
                streaming_pull_future.cancel()  # Trigger the shutdown.
                streaming_pull_future.result()  # Block until the shutdown is complete.
        except Exception as e:
            print(
                f"Exception occurred when creating subscription and subscribing to it: {e}"
            )
    except Exception as e:
        print(f"Exception occurred when attempting optimistic subscribe: {e}")

C++

Prima di provare questo esempio, segui le istruzioni di configurazione di C++ nella guida rapida all'utilizzo delle librerie client. Per ulteriori informazioni, consulta la documentazione di riferimento dell'API Pub/Sub C++.

auto process_response = [](gc::StatusOr<pubsub::PullResponse> response) {
  if (response) {
    std::cout << "Received message " << response->message << "\n";
    std::move(response->handler).ack();
    return gc::Status();
  }
  if (response.status().code() == gc::StatusCode::kUnavailable &&
      response.status().message() == "no messages returned") {
    std::cout << "No messages returned from Pull()\n";
    return gc::Status();
  }
  return response.status();
};

// Instead of checking if the subscription exists, optimistically try to
// consume from the subscription.
auto status = process_response(subscriber.Pull());
if (status.ok()) return;
if (status.code() != gc::StatusCode::kNotFound) throw std::move(status);

// Since the subscription does not exist, create the subscription.
pubsub_admin::SubscriptionAdminClient subscription_admin_client(
    pubsub_admin::MakeSubscriptionAdminConnection());
google::pubsub::v1::Subscription request;
request.set_name(
    pubsub::Subscription(project_id, subscription_id).FullName());
request.set_topic(
    pubsub::Topic(project_id, std::move(topic_id)).FullName());
auto sub = subscription_admin_client.CreateSubscription(request);
if (!sub) throw std::move(sub).status();

// Consume from the new subscription.
status = process_response(subscriber.Pull());
if (!status.ok()) throw std::move(status);