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 avere il ruolo di gestione dell'identità e dell'accesso Editor Pub/Sub (roles/pubsub.editor) nel 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 eseguito quanto segue:

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

  • È stato specificato un nome per l'abbonamento.

  • È stato specificato il nome di un argomento esistente a cui vuoi allegare l'iscrizione.

  • Se crei un abbonamento push, specifica https:// in lettere minuscole (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 account di servizio possono eseguire azioni sulle risorse Pub/Sub. Se 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 record dettagliato di tutte le modifiche alle autorizzazioni, consentendoti di identificare la fonte di questi problemi.

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

  1. Ottieni le autorizzazioni necessarie per visualizzare Esplora log.

    Per ulteriori informazioni, consulta 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. Ecco 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 di eventuali 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 di quali sono state queste modifiche. Questo può essere utile per risolvere problemi come utenti che non riescono a pubblicare in argomenti o ad abbonarsi a iscrizioni, applicazioni a cui è stato negato l'accesso alle risorse Pub/Sub o modifiche impreviste nel controllo dell'accesso.

    • protoPayload.status.code=7: utilizza questa query quando riscontri errori esplicitamente correlati alle autorizzazioni. In questo modo puoi individuare con precisione quali azioni 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 potrebbero causare il rifiuto dell'autorizzazione.

  5. Analizza i log per determinare fattori quali il timestamp dell'evento, il principale 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 account utente o di servizio con autorizzazioni sufficienti elimina intenzionalmente l'abbonamento.

  • Una sottoscrizione viene eliminata 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:

  1. Nella console Google Cloud, vai alla pagina degli abbonamenti Pub/Sub e verifica che l'abbonamento non sia più elencato. Per ulteriori informazioni su come elencare gli abbonamenti, consulta Elenca un abbonamento.

  2. Controlla i log di controllo. Vai a Esplora log. Utilizza il filtro protoPayload.methodName="google.pubsub.v1.Subscriber.DeleteSubscription" per trovare le iscrizioni eliminate. Esamina i log per determinare se qualcuno ha eliminato l'abbonamento o se è stato eliminato per 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, consulta Risolvere i problemi di Pub/Sub con i log di controllo.

403 (Forbidden) errore

Se ricevi questo errore, procedi nel seguente modo:

  • Assicurati di aver attivato l'API Pub/Sub nella console Google Cloud.
  • Assicurati che il principale che effettua la richiesta disponga delle autorizzazioni richieste per le risorse dell'API Pub/Sub pertinenti, soprattutto se utilizzi l'API Pub/Sub per la comunicazione tra progetti.

  • Se utilizzi Dataflow, assicurati che sia il servizio{PROJECT_NUMBER}@cloudservices.gserviceaccount.com che l'account di servizio Compute Engine{PROJECT_NUMBER}-compute@developer.gserviceaccount.com dispongano delle autorizzazioni richieste per la risorsa API Pub/Sub pertinente. Per ulteriori informazioni, consulta Autorizzazioni e sicurezza dei flussi di dati.

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

Altri codici di errore comuni

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

Utilizzo di quantità eccessive di operazioni amministrative

Se noti che stai utilizzando troppo della tua quota per le operazioni amministrative, potrebbe essere necessario eseguire il refactoring del codice. Come esempio, considera questo pseudocodice. In questo esempio, viene utilizzata un'operazione amministrativa (GET) per verificare la presenza di un abbonamento prima che tenti di consumarne le risorse. Sia GET sia CREATE sono operazioni di amministratore:

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

Un pattern più efficiente è provare a utilizzare i messaggi dell'abbonamento (supponendo che tu possa essere ragionevolmente certo del nome dell'abbonamento). In questo approccio ottimistico, l'abbonamento viene recuperato o creato 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:

Go

Prima di provare questo esempio, segui le istruzioni di configurazione di Go riportate nella guida rapida di Pub/Sub che utilizza le librerie client. Per ulteriori informazioni, consulta la documentazione di riferimento dell'API Pub/Sub Go.

Per autenticarti a Pub/Sub, configura le Credenziali predefinite dell'applicazione. Per ulteriori informazioni, consulta Configurare l'autenticazione per un ambiente di sviluppo locale.

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

	"cloud.google.com/go/pubsub"
	"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, topicID, subID string) error {
	// projectID := "my-project-id"
	// topicID := "my-topic"
	// subID := "my-sub"
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("pubsub.NewClient: %w", err)
	}
	defer client.Close()

	sub := client.Subscription(subID)

	// 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.
	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 {
				// Since the subscription does not exist, create the subscription.
				s, err := client.CreateSubscription(ctx, subID, pubsub.SubscriptionConfig{
					Topic: client.Topic(topicID),
				})
				if err != nil {
					return err
				}
				fmt.Fprintf(w, "Created subscription: %q\n", subID)

				// Pull from the new subscription.
				err = s.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 riportate nella guida rapida di Pub/Sub che utilizza le librerie client. Per ulteriori informazioni, consulta la documentazione di riferimento dell'API Pub/Sub Java.

Per autenticarti a Pub/Sub, configura le Credenziali predefinite dell'applicazione. Per ulteriori informazioni, consulta Configurare l'autenticazione per un ambiente di sviluppo locale.


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 riportate nella guida rapida di Pub/Sub che utilizza le librerie client. Per ulteriori informazioni, consulta la documentazione di riferimento dell'API Pub/Sub Node.js.

Per autenticarti a Pub/Sub, configura le Credenziali predefinite dell'applicazione. Per ulteriori informazioni, consulta Configurare l'autenticazione per un ambiente di sviluppo locale.

/**
 * 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);
}

Python

Prima di provare questo esempio, segui le istruzioni di configurazione di Python riportate nella guida rapida di Pub/Sub che utilizza le librerie client. Per ulteriori informazioni, consulta la documentazione di riferimento dell'API Pub/Sub Python.

Per autenticarti a Pub/Sub, configura le Credenziali predefinite dell'applicazione. Per ulteriori informazioni, consulta Configurare l'autenticazione per un ambiente di sviluppo locale.

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++ riportate nella guida rapida di Pub/Sub che utilizza le librerie client. Per ulteriori informazioni, consulta la documentazione di riferimento dell'API Pub/Sub C++.

Per autenticarti a Pub/Sub, configura le Credenziali predefinite dell'applicazione. Per ulteriori informazioni, consulta Configurare l'autenticazione per un ambiente di sviluppo locale.

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);

Node.js (TypeScript)

Prima di provare questo esempio, segui le istruzioni di configurazione di Node.js riportate nella guida rapida di Pub/Sub che utilizza le librerie client. Per saperne di più, consulta la documentazione di riferimento dell'API Pub/Sub Node.js.

Per autenticarti a Pub/Sub, configura le Credenziali predefinite dell'applicazione. Per ulteriori informazioni, consulta Configurare l'autenticazione per un ambiente di sviluppo locale.

/**
 * 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);
}