Genau einmal zugestellt

Auf dieser Seite wird beschrieben, wie Sie Nachrichten mit der genau einmal-Funktion von Pub/Sub empfangen und bestätigen. So können Sie die doppelte Verarbeitung von Nachrichten nachverfolgen und verhindern. Wenn die Funktion aktiviert ist, bietet Pub/Sub die folgende Semantik:

  • Abonnenten können feststellen, ob die Bestätigungen von Nachrichten erfolgreich waren.

  • Nach der erfolgreichen Bestätigung der Nachricht erfolgt keine erneute Zustellung.

  • Solange eine Nachricht ausstehend ist, erfolgt keine erneute Zustellung. Eine Nachricht gilt als ausstehend, bis die Bestätigungsfrist abgelaufen ist oder die Nachricht bestätigt wurde.

  • Bei mehreren gültigen Übermittlungen kann aufgrund des Ablaufs der Bestätigungsfrist oder einer vom Client initiierten negativen Bestätigung nur die letzte Bestätigungs-ID verwendet werden, um die Nachricht zu bestätigen. Alle Anfragen mit einer vorherigen Bestätigungs-ID schlagen fehl.

Wenn die Funktion „Genau einmal“ aktiviert ist, können Abonnenten dafür sorgen, dass Nachrichten nur einmal verarbeitet werden. Beachten Sie dazu die folgenden Richtlinien:

  • Bestätigen Sie Nachrichten innerhalb der Bestätigungsfrist.

  • Behalten Sie Informationen zum Fortschritt der Verarbeitung einer Nachricht im Auge, bis sie bestätigt wurde.

  • Anhand der Informationen zum Fortschritt der Verarbeitung einer Nachricht können Sie verhindern, dass Sie doppelte Arbeit leisten müssen, wenn eine Bestätigung fehlschlägt.

Nur der Pull-Abotyp unterstützt die Übermittlung genau einmal, einschließlich Abonnenten, die die StreamingPull API verwenden. Push- und Exportabos unterstützen die genau einmalige Zustellung nicht.

Pub/Sub unterstützt die genau einmalige Zustellung innerhalb einer Cloud-Region auf Grundlage einer von Pub/Sub definierten eindeutigen Nachrichten-ID.

Erneute Übermittlung im Vergleich zu Duplikaten

Es ist wichtig, den Unterschied zwischen erwarteten und unerwarteten erneuten Übermittlungen zu verstehen.

  • Eine erneute Zustellung kann entweder aufgrund einer vom Client initiierten negativen Bestätigung einer Nachricht oder wenn der Client die Bestätigungsfrist der Nachricht nicht verlängert, bevor sie abläuft, erfolgen. Wiederholte Übermittlungen gelten als gültig und das System funktioniert wie vorgesehen.

    Informationen zur Fehlerbehebung bei erneuten Übermittlungen finden Sie unter Duplikate.

  • Eine Nachricht gilt als Duplikat, wenn sie nach einer erfolgreichen Bestätigung oder vor Ablauf der Bestätigungsfrist noch einmal gesendet wird.

  • Eine noch einmal übermittelte Nachricht behält zwischen den Übermittlungsversuchen dieselbe Nachrichten-ID.

Bei Abos mit aktivierter Funktion „Genau einmal zugestellt“ werden keine doppelten Zustellungen ausgeführt.

Unterstützung der genau einmaligen Zustellung in Clientbibliotheken

  • Unterstützte Clientbibliotheken haben eine Schnittstelle für die Bestätigung mit Antwort (z. B. Go). Über diese Benutzeroberfläche können Sie prüfen, ob die Bestätigungsanfrage erfolgreich war. Wenn die Bestätigungsanfrage erfolgreich ist, erhalten die Clients garantiert keine erneute Zustellung. Wenn die Bestätigungsanfrage fehlschlägt, erhalten die Kunden eine erneute Zustellung.

  • Clients können die unterstützten Clientbibliotheken auch ohne die Bestätigungsoberfläche verwenden. In solchen Fällen können die Bestätigungsfehler jedoch zu einer stillen erneuten Zustellung von Nachrichten führen.

  • Unterstützte Clientbibliotheken haben Schnittstellen zum Festlegen der Mindestdauer der Verlängerung der Laufzeit (z. B. Go). Sie müssen den Wert für die minimale Verlängerung der Laufzeit auf eine hohe Zahl festlegen, um Netzwerkfehler bei der Bestätigung zu vermeiden. Der Höchstwert beträgt 600 Sekunden.

Die Standardwerte und der Bereich für die Variablen, die sich auf die Zustellung genau einmal beziehen, sowie die Namen der Variablen können sich je nach Clientbibliothek unterscheiden. In der Java-Clientbibliothek werden beispielsweise die folgenden Variablen für die Zustellung genau einmal gesteuert.

Variable Beschreibung Wert
setEnableExactlyOnceDelivery Aktiviert oder deaktiviert die Funktion „Genau einmal zugestellt“. „wahr“ oder „falsch“ (Standardeinstellung: „falsch“)
minDurationPerAckExtension Die Mindestdauer in Sekunden, die für die Verlängerung der Frist für die Bestätigung der Änderung verwendet werden soll. Bereich: 0 bis 600; Standard: „none“
maxDurationPerAckExtension Die maximale Zeit in Sekunden, um die die Frist für die Bestätigung der Änderung verlängert werden kann. Bereich: 0 bis 600; Standard: „none“

Bei der genau einmal erfolgenden Zustellung schlägt die modifyAckDeadline- oder acknowledgment-Anfrage an Pub/Sub fehl, wenn die Bestätigungs-ID bereits abgelaufen ist. In solchen Fällen betrachtet der Dienst die abgelaufene Bestätigungs-ID als ungültig, da möglicherweise bereits eine neue Zustellung in Bearbeitung ist. Das ist so gewollt, damit die Nachrichten genau einmal zugestellt werden. Sie sehen dann, dass acknowledgment- und ModifyAckDeadline-Anfragen eine INVALID_ARGUMENT-Antwort zurückgeben. Wenn die Zustellung genau einmal deaktiviert ist, wird bei abgelaufenen Bestätigungs-IDs OK zurückgegeben.

Damit acknowledgment- und ModifyAckDeadline-Anfragen gültige Bestätigungs-IDs haben, sollten Sie den Wert für minDurationPerAckExtension auf eine hohe Zahl festlegen.

Regionale Einschränkungen

Die Garantie für die genau einmalige Zustellung gilt nur, wenn Abonnenten eine Verbindung zum Dienst in derselben Region herstellen. Wenn Ihre Abonnentenanwendung auf mehrere Regionen verteilt ist, kann es zu doppelten Nachrichtenzustellungen kommen, auch wenn die Zustellung genau einmal aktiviert ist. Publisher können Nachrichten an jede Region senden und die Garantie, dass Nachrichten nur einmal gesendet werden, bleibt bestehen.

Wenn Sie Ihre Anwendung in Google Cloud ausführen, wird standardmäßig eine Verbindung zum Pub/Sub-Endpunkt in derselben Region hergestellt. Wenn Sie Ihre Anwendung also in einer einzelnen Region in Google Cloud ausführen, interagieren Sie in der Regel mit einer einzelnen Region.

Wenn Sie Ihre Abonnentenanwendung außerhalb von Google Cloud oder in mehreren Regionen ausführen, können Sie eine Verbindung zu einer einzelnen Region herstellen, indem Sie beim Konfigurieren Ihres Pub/Sub-Clients einen Standortendpunkt verwenden. Alle Standortendpunkte für Pub/Sub verweisen auf einzelne Regionen. Weitere Informationen zu Standortendpunkten finden Sie unter Pub/Sub-Endpunkte. Eine Liste aller standortbezogenen Endpunkte für Pub/Sub finden Sie unter Liste der standortbezogenen Endpunkte.

Abos mit genau einmaliger Zustellung erstellen

Sie können ein Abo mit einer Zustellung genau einmal mit der Google Cloud Console, der Google Cloud CLI, der Clientbibliothek oder der Pub/Sub API erstellen.

Pull-Abo

Console

So erstellen Sie ein Pull-Abo mit der Zustellung genau einmal:

  1. Öffnen Sie in der Google Cloud Console die Seite Abos.

    Zu den Abos

  2. Klicken Sie auf Abo erstellen.

  3. Geben Sie die Abo-ID ein.

  4. Wählen Sie im Drop-down-Menü ein Thema aus oder erstellen Sie ein Thema.

    Das Abo erhält Nachrichten aus dem Thema.

  5. Wählen Sie im Abschnitt Genau einmal zugestellt die Option Genau einmal zugestellt aktivieren aus.

  6. Klicken Sie auf Erstellen.

gcloud

Verwenden Sie zum Erstellen eines Pull-Abos mit einer Zustellung genau einmal den Befehl gcloud pubsub subscriptions create mit dem Flag --enable-exactly-once-delivery:

gcloud pubsub subscriptions create SUBSCRIPTION_ID \
  --topic=TOPIC_ID \
  --enable-exactly-once-delivery

Ersetzen Sie Folgendes:

  • SUBSCRIPTION_ID: Die ID des zu erstellenden Abos
  • TOPIC_ID: Die ID des Themas, das an das Abo angehängt werden soll

REST

Wenn Sie ein Abo mit genau einmal erfolgender Zustellung erstellen möchten, verwenden Sie die Methode projects.subscriptions.create.

PUT https://pubsub.googleapis.com/v1/projects/PROJECT_ID/subscriptions/SUBSCRIPTION_ID
Authorization: Bearer $(gcloud auth print-access-token)

Ersetzen Sie Folgendes:

  • PROJECT_ID: die Projekt-ID des Projekts, in dem das Abo erstellt werden soll
  • SUBSCRIPTION_ID: Die ID des zu erstellenden Abos

Wenn Sie ein Pull-Abo mit der Zustellung genau einmal erstellen möchten, geben Sie dies im Anfragetext an:

{
  "topic": "projects/PROJECT_ID/topics/TOPIC_ID",
  "enableExactlyOnceDelivery": true,
}

Ersetzen Sie Folgendes:

  • PROJECT_ID: Die Projekt-ID des Projekts mit dem Thema
  • TOPIC_ID: Die ID des Themas, das an das Abo angehängt werden soll

C++

Bevor Sie dieses Beispiel testen, folgen Sie der Einrichtungsanleitung für C++ in der Kurzanleitung: Clientbibliotheken verwenden. Weitere Informationen finden Sie in der Referenzdokumentation zur Pub/Sub C++ API.

namespace pubsub = ::google::cloud::pubsub;
namespace pubsub_admin = ::google::cloud::pubsub_admin;
[](pubsub_admin::SubscriptionAdminClient client,
   std::string const& project_id, std::string const& topic_id,
   std::string const& subscription_id) {
  google::pubsub::v1::Subscription request;
  request.set_name(
      pubsub::Subscription(project_id, subscription_id).FullName());
  request.set_topic(pubsub::Topic(project_id, topic_id).FullName());
  request.set_enable_exactly_once_delivery(true);
  auto sub = client.CreateSubscription(request);
  if (sub.status().code() == google::cloud::StatusCode::kAlreadyExists) {
    std::cout << "The subscription already exists\n";
    return;
  }
  if (!sub) throw std::move(sub).status();

  std::cout << "The subscription was successfully created: "
            << sub->DebugString() << "\n";
}

C#

Bevor Sie dieses Beispiel testen, folgen Sie der Einrichtungsanleitung für C# in der Schnellstart-Anleitung: Clientbibliotheken verwenden. Weitere Informationen finden Sie in der Referenzdokumentation zu Pub/Sub C# API.


using Google.Cloud.PubSub.V1;
using Grpc.Core;

public class CreateSubscriptionWithExactlyOnceDeliverySample
{
    public Subscription CreateSubscriptionWithExactlyOnceDelivery(string projectId, string topicId, string subscriptionId)
    {
        SubscriberServiceApiClient subscriber = SubscriberServiceApiClient.Create();
        TopicName topicName = TopicName.FromProjectTopic(projectId, topicId);
        SubscriptionName subscriptionName = SubscriptionName.FromProjectSubscription(projectId, subscriptionId);

        var subscriptionRequest = new Subscription
        {
            SubscriptionName = subscriptionName,
            TopicAsTopicName = topicName,
            EnableExactlyOnceDelivery = true
        };

        Subscription subscription = null;

        try
        {
            subscription = subscriber.CreateSubscription(subscriptionRequest);
        }
        catch (RpcException e) when (e.Status.StatusCode == StatusCode.AlreadyExists)
        {
            // Already exists.  That's fine.
        }
        return subscription;
    }
}

Go

Bevor Sie dieses Beispiel testen, folgen Sie der Einrichtungsanleitung für Go in der Schnellstart-Anleitung: Clientbibliotheken verwenden. Weitere Informationen finden Sie in der Referenzdokumentation zu Pub/Sub Go API.

import (
	"context"
	"fmt"
	"io"

	"cloud.google.com/go/pubsub"
)

func createSubscriptionWithExactlyOnceDelivery(w io.Writer, projectID, subID string, topic *pubsub.Topic) error {
	// projectID := "my-project-id"
	// subID := "my-sub"
	// topic of type https://godoc.org/cloud.google.com/go/pubsub#Topic
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("pubsub.NewClient: %w", err)
	}
	defer client.Close()

	sub, err := client.CreateSubscription(ctx, subID, pubsub.SubscriptionConfig{
		Topic:                     topic,
		EnableExactlyOnceDelivery: true,
	})
	if err != nil {
		return err
	}
	fmt.Fprintf(w, "Created a subscription with exactly once delivery enabled: %v\n", sub)
	return nil
}

Java

Bevor Sie dieses Beispiel testen, folgen Sie der Einrichtungsanleitung für Java in der Kurzanleitung: Clientbibliotheken verwenden. Weitere Informationen finden Sie in der Referenzdokumentation zu Pub/Sub Java API.

import com.google.cloud.pubsub.v1.SubscriptionAdminClient;
import com.google.pubsub.v1.ProjectSubscriptionName;
import com.google.pubsub.v1.ProjectTopicName;
import com.google.pubsub.v1.Subscription;
import java.io.IOException;

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

    createSubscriptionWithExactlyOnceDeliveryExample(projectId, topicId, subscriptionId);
  }

  public static void createSubscriptionWithExactlyOnceDeliveryExample(
      String projectId, String topicId, String subscriptionId) throws IOException {
    try (SubscriptionAdminClient subscriptionAdminClient = SubscriptionAdminClient.create()) {

      ProjectTopicName topicName = ProjectTopicName.of(projectId, topicId);
      ProjectSubscriptionName subscriptionName =
          ProjectSubscriptionName.of(projectId, subscriptionId);

      Subscription subscription =
          subscriptionAdminClient.createSubscription(
              Subscription.newBuilder()
                  .setName(subscriptionName.toString())
                  .setTopic(topicName.toString())
                  // Enable exactly once delivery in the subscription.
                  .setEnableExactlyOnceDelivery(true)
                  .build());

      System.out.println(
          "Created a subscription with exactly once delivery enabled: "
              + subscription.getAllFields());
    }
  }
}

Python

Bevor Sie dieses Beispiel testen, folgen Sie der Einrichtungsanleitung für Python in der Schnellstart-Anleitung: Clientbibliotheken verwenden. Weitere Informationen finden Sie in der Referenzdokumentation zu Pub/Sub Python API.

from google.cloud import pubsub_v1

# TODO(developer): Choose an existing topic.
# project_id = "your-project-id"
# topic_id = "your-topic-id"
# subscription_id = "your-subscription-id"

publisher = pubsub_v1.PublisherClient()
subscriber = pubsub_v1.SubscriberClient()
topic_path = publisher.topic_path(project_id, topic_id)
subscription_path = subscriber.subscription_path(project_id, subscription_id)

with subscriber:
    subscription = subscriber.create_subscription(
        request={
            "name": subscription_path,
            "topic": topic_path,
            "enable_exactly_once_delivery": True,
        }
    )
    print(
        f"Created subscription with exactly once delivery enabled: {subscription}"
    )

Node.js

Bevor Sie dieses Beispiel testen, folgen Sie der Einrichtungsanleitung für PHP in der Schnellstart-Anleitung: Clientbibliotheken verwenden. Weitere Informationen finden Sie in der Referenzdokumentation zu Pub/Sub Node.js API.

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

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

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

async function createSubscriptionWithExactlyOnceDelivery(
  topicNameOrId,
  subscriptionNameOrId
) {
  // Creates a new subscription
  await pubSubClient
    .topic(topicNameOrId)
    .createSubscription(subscriptionNameOrId, {
      enableExactlyOnceDelivery: true,
    });
  console.log(
    `Created subscription ${subscriptionNameOrId} with exactly-once delivery.`
  );
  console.log(
    'To process messages, remember to check the return value of ackWithResponse().'
  );
}

Node.js

Bevor Sie dieses Beispiel testen, folgen Sie der Einrichtungsanleitung für PHP in der Schnellstart-Anleitung: Clientbibliotheken verwenden. Weitere Informationen finden Sie in der Referenzdokumentation zu Pub/Sub Node.js API.

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

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

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

async function createSubscriptionWithExactlyOnceDelivery(
  topicNameOrId: string,
  subscriptionNameOrId: string
) {
  // Creates a new subscription
  await pubSubClient
    .topic(topicNameOrId)
    .createSubscription(subscriptionNameOrId, {
      enableExactlyOnceDelivery: true,
    });
  console.log(
    `Created subscription ${subscriptionNameOrId} with exactly-once delivery.`
  );
  console.log(
    'To process messages, remember to check the return value of ackWithResponse().'
  );
}

Ruby

Bevor Sie dieses Beispiel testen, folgen Sie der Einrichtungsanleitung für Ruby in der Schnellstart-Anleitung: Clientbibliotheken verwenden. Weitere Informationen finden Sie in der Referenzdokumentation zu Pub/Sub Ruby API.

require "google/cloud/pubsub"

# Shows how to create a new subscription with exactly once delivery enabled
class PubsubCreateSubscriptionWithExactlyOnceDelivery
  def create_subscription_with_exactly_once_delivery project_id:, topic_id:, subscription_id:
    pubsub = Google::Cloud::Pubsub.new project_id: project_id
    topic = pubsub.topic topic_id
    subscription = topic.subscribe subscription_id, enable_exactly_once_delivery: true
    puts "Created subscription with exactly once delivery enabled: #{subscription_id}"
  end

  def self.run
    # TODO(developer): Replace these variables before running the sample.
    project_id = "your-project-id"
    topic_id = "your-topic-id"
    subscription_id = "id-for-new-subcription"
    pubsub_create_subscription_with_exactly_once_delivery = PubsubCreateSubscriptionWithExactlyOnceDelivery.new
    pubsub_create_subscription_with_exactly_once_delivery.create_subscription_with_exactly_once_delivery(
      project_id: project_id,
      topic_id: topic_id,
      subscription_id: subscription_id
    )
  end
end

if $PROGRAM_NAME == __FILE__
  PubsubCreateSubscriptionWithExactlyOnceDelivery.run
end

PHP

Folgen Sie der Einrichtungsanleitung für PHP unter Schnellstart: Clientbibliotheken verwenden, bevor Sie dieses Beispiel ausprobieren. Weitere Informationen finden Sie in der Referenzdokumentation zur PHP-API von Pub/Sub.

use Google\Cloud\PubSub\PubSubClient;

/**
 * Creates a Pub/Sub subscription with `Exactly Once Delivery` enabled.
 *
 * @param string $projectId  The Google project ID.
 * @param string $topicName  The Pub/Sub topic name.
 * @param string $subscriptionName  The Pub/Sub subscription name.
 */
function create_subscription_with_exactly_once_delivery(
    string $projectId,
    string $topicName,
    string $subscriptionName
): void {
    $pubsub = new PubSubClient([
        'projectId' => $projectId,
    ]);
    $topic = $pubsub->topic($topicName);
    $subscription = $topic->subscription($subscriptionName);
    $subscription->create([
        'enableExactlyOnceDelivery' => true
    ]);

    // Exactly Once Delivery status for the subscription
    $status = $subscription->info()['enableExactlyOnceDelivery'];

    printf('Subscription created with exactly once delivery status: %s' . PHP_EOL, $status ? 'true' : 'false');
}

Abo mit genau einmal zugestellten Nachrichten

Im Folgenden findest du einige Codebeispiele für die Registrierung mit Übermittlung genau einmal mithilfe der Clientbibliothek.

Pull-Abo

Go

Folgen Sie der Einrichtungsanleitung für Go in der Kurzanleitung zur Verwendung von Clientbibliotheken, bevor Sie dieses Beispiel anwenden. Weitere Informationen finden Sie in der Referenzdokumentation zur Pub/Sub Go API.

Richten Sie die Standardanmeldedaten für Anwendungen ein, um sich bei Pub/Sub zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

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

	"cloud.google.com/go/pubsub"
	"google.golang.org/api/option"
)

// receiveMessagesWithExactlyOnceDeliveryEnabled instantiates a subscriber client.
// This differs from regular subscribing since you must call msg.AckWithResult()
// or msg.NackWithResult() instead of the regular Ack/Nack methods.
// When exactly once delivery is enabled on the subscription, the message is
// guaranteed to not be delivered again if the ack result succeeds.
func receiveMessagesWithExactlyOnceDeliveryEnabled(w io.Writer, projectID, subID string) error {
	// projectID := "my-project-id"
	// subID := "my-sub"
	ctx := context.Background()

	// Pub/Sub's exactly once delivery guarantee only applies when subscribers connect to the service in the same region.
	// For list of locational endpoints for Pub/Sub, see https://cloud.google.com/pubsub/docs/reference/service_apis_overview#list_of_locational_endpoints
	client, err := pubsub.NewClient(ctx, projectID, option.WithEndpoint("us-west1-pubsub.googleapis.com:443"))
	if err != nil {
		return fmt.Errorf("pubsub.NewClient: %w", err)
	}
	defer client.Close()

	sub := client.Subscription(subID)
	// Set MinExtensionPeriod high to avoid any unintentional
	// acknowledgment expirations (e.g. due to network events).
	// This can lead to high tail latency in case of client crashes.
	sub.ReceiveSettings.MinExtensionPeriod = 600 * time.Second

	// 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()
	err = sub.Receive(ctx, func(ctx context.Context, msg *pubsub.Message) {
		fmt.Fprintf(w, "Got message: %q\n", string(msg.Data))
		r := msg.AckWithResult()
		// Block until the result is returned and a pubsub.AcknowledgeStatus
		// is returned for the acked message.
		status, err := r.Get(ctx)
		if err != nil {
			fmt.Fprintf(w, "MessageID: %s failed when calling result.Get: %v", msg.ID, err)
		}

		switch status {
		case pubsub.AcknowledgeStatusSuccess:
			fmt.Fprintf(w, "Message successfully acked: %s", msg.ID)
		case pubsub.AcknowledgeStatusInvalidAckID:
			fmt.Fprintf(w, "Message failed to ack with response of Invalid. ID: %s", msg.ID)
		case pubsub.AcknowledgeStatusPermissionDenied:
			fmt.Fprintf(w, "Message failed to ack with response of Permission Denied. ID: %s", msg.ID)
		case pubsub.AcknowledgeStatusFailedPrecondition:
			fmt.Fprintf(w, "Message failed to ack with response of Failed Precondition. ID: %s", msg.ID)
		case pubsub.AcknowledgeStatusOther:
			fmt.Fprintf(w, "Message failed to ack with response of Other. ID: %s", msg.ID)
		default:
		}
	})
	if err != nil {
		return fmt.Errorf("got err from sub.Receive: %w", err)
	}
	return nil
}

Java

Folgen Sie der Einrichtungsanleitung für Java in der Kurzanleitung zur Verwendung von Clientbibliotheken, bevor Sie dieses Beispiel anwenden. Weitere Informationen finden Sie in der Referenzdokumentation zur Pub/Sub Java API.

Richten Sie die Standardanmeldedaten für Anwendungen ein, um sich bei Pub/Sub zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.


import com.google.cloud.pubsub.v1.AckReplyConsumerWithResponse;
import com.google.cloud.pubsub.v1.AckResponse;
import com.google.cloud.pubsub.v1.MessageReceiverWithAckResponse;
import com.google.cloud.pubsub.v1.Subscriber;
import com.google.pubsub.v1.ProjectSubscriptionName;
import com.google.pubsub.v1.PubsubMessage;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class SubscribeWithExactlyOnceConsumerWithResponseExample {
  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";

    subscribeWithExactlyOnceConsumerWithResponseExample(projectId, subscriptionId);
  }

  public static void subscribeWithExactlyOnceConsumerWithResponseExample(
      String projectId, String subscriptionId) {
    ProjectSubscriptionName subscriptionName =
        ProjectSubscriptionName.of(projectId, subscriptionId);

    // Instantiate an asynchronous message receiver using `AckReplyConsumerWithResponse`
    // instead of `AckReplyConsumer` to get a future that tracks the result of the ack call.
    // When exactly once delivery is enabled on the subscription, the message is guaranteed
    // to not be delivered again if the ack future succeeds.
    MessageReceiverWithAckResponse receiverWithResponse =
        (PubsubMessage message, AckReplyConsumerWithResponse consumerWithResponse) -> {
          try {
            // Handle incoming message, then ack the message, and receive an ack response.
            System.out.println("Message received: " + message.getData().toStringUtf8());
            Future<AckResponse> ackResponseFuture = consumerWithResponse.ack();

            // Retrieve the completed future for the ack response from the server.
            AckResponse ackResponse = ackResponseFuture.get();

            switch (ackResponse) {
              case SUCCESSFUL:
                // Success code means that this MessageID will not be delivered again.
                System.out.println("Message successfully acked: " + message.getMessageId());
                break;
              case INVALID:
                System.out.println(
                    "Message failed to ack with a response of Invalid. Id: "
                        + message.getMessageId());
                break;
              case PERMISSION_DENIED:
                System.out.println(
                    "Message failed to ack with a response of Permission Denied. Id: "
                        + message.getMessageId());
                break;
              case FAILED_PRECONDITION:
                System.out.println(
                    "Message failed to ack with a response of Failed Precondition. Id: "
                        + message.getMessageId());
                break;
              case OTHER:
                System.out.println(
                    "Message failed to ack with a response of Other. Id: "
                        + message.getMessageId());
                break;
              default:
                break;
            }
          } catch (InterruptedException | ExecutionException e) {
            System.out.println(
                "MessageId: " + message.getMessageId() + " failed when retrieving future");
          } catch (Throwable t) {
            System.out.println("Throwable caught" + t.getMessage());
          }
        };

    Subscriber subscriber = null;
    try {
      subscriber = Subscriber.newBuilder(subscriptionName, receiverWithResponse).build();
      // Start the subscriber.
      subscriber.startAsync().awaitRunning();
      System.out.printf("Listening for messages on %s:\n", subscriptionName.toString());
      // Allow the subscriber to run for 30s unless an unrecoverable error occurs.
      subscriber.awaitTerminated(30, TimeUnit.SECONDS);
    } catch (TimeoutException timeoutException) {
      // Shut down the subscriber after 30s. Stop receiving messages.
      subscriber.stopAsync();
    }
  }
}

Node.js

Folgen Sie der Einrichtungsanleitung für Node.js in der Kurzanleitung zur Verwendung von Clientbibliotheken, bevor Sie dieses Beispiel anwenden. Weitere Informationen finden Sie in der Referenzdokumentation zur Pub/Sub Node.js API.

Richten Sie die Standardanmeldedaten für Anwendungen ein, um sich bei Pub/Sub zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

/**
 * TODO(developer): Uncomment this variable before running the sample.
 */
// const subscriptionNameOrId = 'YOUR_SUBSCRIPTION_NAME_OR_ID';

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

// Pub/Sub's exactly once delivery guarantee only applies when subscribers connect to the service in the same region.
// For list of locational endpoints for Pub/Sub, see https://cloud.google.com/pubsub/docs/reference/service_apis_overview#list_of_locational_endpoints
const pubSubClient = new PubSub({
  apiEndpoint: 'us-west1-pubsub.googleapis.com:443',
});

async function listenForMessagesWithExactlyOnceDelivery(
  subscriptionNameOrId,
  timeout
) {
  // References an existing subscription
  const subscription = pubSubClient.subscription(subscriptionNameOrId);

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

    // Use `ackWithResponse()` instead of `ack()` to get a Promise that tracks
    // the result of the acknowledge call. When exactly-once delivery is enabled
    // on the subscription, the message is guaranteed not to be delivered again
    // if the ack Promise resolves.
    try {
      // When the Promise resolves, the value is always AckResponses.Success,
      // signaling that the ack was accepted. Note that you may call this
      // method on a subscription without exactly-once delivery, but it will
      // always return AckResponses.Success.
      await message.ackWithResponse();
      console.log(`Ack for message ${message.id} successful.`);
    } catch (e) {
      // In all other cases, the error passed on reject will explain why. This
      // is only for permanent failures; transient errors are retried automatically.
      const ackError = e;
      console.log(
        `Ack for message ${message.id} failed with error: ${ackError.errorCode}`
      );
    }
  };

  // Listen for new messages until timeout is hit
  subscription.on('message', messageHandler);

  setTimeout(() => {
    subscription.removeListener('message', messageHandler);
    console.log(`${messageCount} message(s) received.`);
  }, timeout * 1000);
}

PHP

Folgen Sie der Einrichtungsanleitung für PHP in der Kurzanleitung zur Verwendung von Clientbibliotheken, bevor Sie dieses Beispiel anwenden. Weitere Informationen finden Sie in der Referenzdokumentation zur Pub/Sub PHP API.

Richten Sie die Standardanmeldedaten für Anwendungen ein, um sich bei Pub/Sub zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

use Google\Cloud\PubSub\PubSubClient;

/**
 * Subscribe and pull messages from a subscription
 * with `Exactly Once Delivery` enabled.
 *
 * @param string $projectId
 * @param string $subscriptionId
 */
function subscribe_exactly_once_delivery(
    string $projectId,
    string $subscriptionId
): void {
    $pubsub = new PubSubClient([
        'projectId' => $projectId,
    ]);

    $subscription = $pubsub->subscription($subscriptionId);
    $messages = $subscription->pull();

    foreach ($messages as $message) {
        // When exactly once delivery is enabled on the subscription,
        // the message is guaranteed to not be delivered again if the ack succeeds.
        // Passing the `returnFailures` flag retries any temporary failures received
        // while acking the msg and also returns any permanently failed msgs.
        // Passing this flag on a subscription with exactly once delivery disabled
        // will always return an empty array.
        $failedMsgs = $subscription->acknowledge($message, ['returnFailures' => true]);

        if (empty($failedMsgs)) {
            printf('Acknowledged message: %s' . PHP_EOL, $message->data());
        } else {
            // Either log or store the $failedMsgs to be retried later
        }
    }
}

Python

Folgen Sie der Einrichtungsanleitung für Python in der Kurzanleitung zur Verwendung von Clientbibliotheken, bevor Sie dieses Beispiel anwenden. Weitere Informationen finden Sie in der Referenzdokumentation zur Pub/Sub Python API.

Richten Sie die Standardanmeldedaten für Anwendungen ein, um sich bei Pub/Sub zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

from concurrent.futures import TimeoutError
from google.cloud import pubsub_v1
from google.cloud.pubsub_v1.subscriber import exceptions as sub_exceptions

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

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)

def callback(message: pubsub_v1.subscriber.message.Message) -> None:
    print(f"Received {message}.")

    # Use `ack_with_response()` instead of `ack()` to get a future that tracks
    # the result of the acknowledge call. When exactly-once delivery is enabled
    # on the subscription, the message is guaranteed to not be delivered again
    # if the ack future succeeds.
    ack_future = message.ack_with_response()

    try:
        # Block on result of acknowledge call.
        # When `timeout` is not set, result() will block indefinitely,
        # unless an exception is encountered first.
        ack_future.result(timeout=timeout)
        print(f"Ack for message {message.message_id} successful.")
    except sub_exceptions.AcknowledgeError as e:
        print(
            f"Ack for message {message.message_id} failed with error: {e.error_code}"
        )

streaming_pull_future = subscriber.subscribe(subscription_path, callback=callback)
print(f"Listening for messages on {subscription_path}..\n")

# Wrap subscriber in a 'with' block to automatically call close() when done.
with subscriber:
    try:
        # When `timeout` is not set, result() will block indefinitely,
        # unless an exception is encountered first.
        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.

Ruby

Folgen Sie der Einrichtungsanleitung für Ruby in der Kurzanleitung zur Verwendung von Clientbibliotheken, bevor Sie dieses Beispiel anwenden. Weitere Informationen finden Sie in der Referenzdokumentation zur Pub/Sub Ruby API.

Richten Sie die Standardanmeldedaten für Anwendungen ein, um sich bei Pub/Sub zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

require "google/cloud/pubsub"

# Shows how to register callback to acknowledge method and access the result passed in
class PubsubSubscriberExactlyOnceDelivery
  def subscriber_exactly_once_delivery project_id:, topic_id:, subscription_id:
    pubsub = Google::Cloud::Pubsub.new project_id: project_id
    topic = pubsub.topic topic_id
    subscription = pubsub.subscription subscription_id
    subscriber   = subscription.listen do |received_message|
      puts "Received message: #{received_message.data}"

      # Pass in callback to access the acknowledge result.
      # For subscription with Exactly once delivery disabled the result will be success always.
      received_message.acknowledge! do |result|
        puts "Acknowledge result's status: #{result.status}"
      end
    end

    subscriber.start
    # Let the main thread sleep for 60 seconds so the thread for listening
    # messages does not quit
    sleep 60
    subscriber.stop.wait!
  end

  def self.run
    # TODO(developer): Replace these variables before running the sample.
    project_id = "your-project-id"
    topic_id = "your-topic-id"
    subscription_id = "id-for-new-subcription" # subscription with exactly once delivery enabled
    PubsubSubscriberExactlyOnceDelivery.new.subscriber_exactly_once_delivery project_id: project_id,
                                                                             topic_id: topic_id,
                                                                             subscription_id: subscription_id
  end
end

if $PROGRAM_NAME == __FILE__
  PubsubSubscriberExactlyOnceDelivery.run
end

C++

Folgen Sie der Einrichtungsanleitung für C++ in der Kurzanleitung zur Verwendung von Clientbibliotheken, bevor Sie dieses Beispiel anwenden. Weitere Informationen finden Sie in der Referenzdokumentation zur Pub/Sub C++ API.

Richten Sie die Standardanmeldedaten für Anwendungen ein, um sich bei Pub/Sub zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

namespace pubsub = ::google::cloud::pubsub;
auto sample = [](pubsub::Subscriber subscriber) {
  return subscriber.Subscribe(
      [&](pubsub::Message const& m, pubsub::ExactlyOnceAckHandler h) {
        std::cout << "Received message " << m << "\n";
        std::move(h).ack().then([id = m.message_id()](auto f) {
          auto status = f.get();
          std::cout << "Message id " << id
                    << " ack() completed with status=" << status << "\n";
        });
        PleaseIgnoreThisSimplifiesTestingTheSamples();
      });
};

C#

Folgen Sie der Einrichtungsanleitung für C# in der Kurzanleitung zur Verwendung von Clientbibliotheken, bevor Sie dieses Beispiel anwenden. Weitere Informationen finden Sie in der Referenzdokumentation zur Pub/Sub C# API.

Richten Sie die Standardanmeldedaten für Anwendungen ein, um sich bei Pub/Sub zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.


using Google.Cloud.PubSub.V1;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using static Google.Cloud.PubSub.V1.SubscriberClient;

public class ExactlyOnceDeliverySubscriberAsyncSample
{
    public async Task<IEnumerable<string>> ExactlyOnceDeliverySubscriberAsync(string projectId, string subscriptionId)
    {
        // subscriptionId should be the ID of an exactly-once delivery subscription.
        SubscriptionName subscriptionName = SubscriptionName.FromProjectSubscription(projectId, subscriptionId);
        SubscriberClient subscriber = await SubscriberClient.CreateAsync(subscriptionName);
        // To get the status of ACKnowledge (ACK) or Not ACKnowledge (NACK) request in exactly once delivery subscriptions,
        // create a subscription handler that inherits from Google.Cloud.PubSub.V1.SubscriptionHandler. 
        // For more information see Google.Cloud.PubSub.V1.SubscriptionHandler reference docs here:
        // https://cloud.google.com/dotnet/docs/reference/Google.Cloud.PubSub.V1/latest/Google.Cloud.PubSub.V1.SubscriptionHandler
        var subscriptionHandler = new SampleSubscriptionHandler();
        Task subscriptionTask = subscriber.StartAsync(subscriptionHandler);
        // The subscriber will be running until it is stopped.
        await Task.Delay(5000);
        await subscriber.StopAsync(CancellationToken.None);
        // Let's make sure that the start task finished successfully after the call to stop.
        await subscriptionTask;
        return subscriptionHandler.SuccessfulAckedIds;
    }

    // Sample handler to handle messages and ACK/NACK responses.
    public class SampleSubscriptionHandler : SubscriptionHandler
    {
        public ConcurrentBag<string> SuccessfulAckedIds { get; } = new ConcurrentBag<string>();

        /// <summary>
        /// The function that processes received messages. It should be thread-safe.
        /// Return <see cref="Reply.Ack"/> to ACKnowledge the message (meaning it won't be received again).
        /// Return <see cref="Reply.Nack"/> to Not ACKnowledge the message (meaning it will be received again).
        /// From the point of view of message acknowledgement, throwing an exception is equivalent to returning <see cref="Reply.Nack"/>.
        /// </summary>
        public override async Task<Reply> HandleMessage(PubsubMessage message, CancellationToken cancellationToken)
        {
            string text = message.Data.ToStringUtf8();
            Console.WriteLine($"Message {message.MessageId}: {text}");
            return await Task.FromResult(Reply.Ack);
        }

        /// <summary>
        /// This method will receive responses for all acknowledge requests.
        /// </summary>
        public override void HandleAckResponses(IReadOnlyList<AckNackResponse> responses)
        {
            foreach (var response in responses)
            {
                if (response.Status == AcknowledgementStatus.Success)
                {
                    SuccessfulAckedIds.Add(response.MessageId);
                }

                string result = response.Status switch
                {
                    AcknowledgementStatus.Success => $"MessageId {response.MessageId} successfully acknowledged.",
                    AcknowledgementStatus.PermissionDenied => $"MessageId {response.MessageId} failed to acknowledge due to a permission denied error.",
                    AcknowledgementStatus.FailedPrecondition => $"MessageId {response.MessageId} failed to acknowledge due to a failed precondition.",
                    AcknowledgementStatus.InvalidAckId => $"MessageId {response.MessageId} failed to acknowledge due an invalid or expired AckId.",
                    AcknowledgementStatus.Other => $"MessageId {response.MessageId} failed to acknowledge due to an unknown reason.",
                    _ => $"Unknown acknowledgement status for messageId {response.MessageId}."
                };

                Console.WriteLine(result);
            }
        }
    }
}

Node.js (TypeScript)

Lesen Sie unter Pub/Sub-Kurzanleitung: Clientbibliotheken verwenden die Anleitung für die Einrichtung von Node.js, bevor Sie dieses Beispiel ausprobieren. Weitere Informationen finden Sie in der Referenzdokumentation zur Pub/Sub Node.js API.

Richten Sie die Standardanmeldedaten für Anwendungen ein, um sich bei Pub/Sub zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

/**
 * TODO(developer): Uncomment this variable before running the sample.
 */
// const subscriptionNameOrId = 'YOUR_SUBSCRIPTION_NAME_OR_ID';

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

// Pub/Sub's exactly once delivery guarantee only applies when subscribers connect to the service in the same region.
// For list of locational endpoints for Pub/Sub, see https://cloud.google.com/pubsub/docs/reference/service_apis_overview#list_of_locational_endpoints
const pubSubClient = new PubSub({
  apiEndpoint: 'us-west1-pubsub.googleapis.com:443',
});

async function listenForMessagesWithExactlyOnceDelivery(
  subscriptionNameOrId: string,
  timeout: number
) {
  // References an existing subscription
  const subscription = pubSubClient.subscription(subscriptionNameOrId);

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

    // Use `ackWithResponse()` instead of `ack()` to get a Promise that tracks
    // the result of the acknowledge call. When exactly-once delivery is enabled
    // on the subscription, the message is guaranteed not to be delivered again
    // if the ack Promise resolves.
    try {
      // When the Promise resolves, the value is always AckResponses.Success,
      // signaling that the ack was accepted. Note that you may call this
      // method on a subscription without exactly-once delivery, but it will
      // always return AckResponses.Success.
      await message.ackWithResponse();
      console.log(`Ack for message ${message.id} successful.`);
    } catch (e) {
      // In all other cases, the error passed on reject will explain why. This
      // is only for permanent failures; transient errors are retried automatically.
      const ackError = e as AckError;
      console.log(
        `Ack for message ${message.id} failed with error: ${ackError.errorCode}`
      );
    }
  };

  // Listen for new messages until timeout is hit
  subscription.on('message', messageHandler);

  setTimeout(() => {
    subscription.removeListener('message', messageHandler);
    console.log(`${messageCount} message(s) received.`);
  }, timeout * 1000);
}

Abos mit der Funktion „Genau einmal zugestellt“ beobachten

Der Messwert subscription/exactly_once_warning_count erfasst die Anzahl der Ereignisse, die zu möglichen erneuten Übermittlungen (gültige oder doppelte) führen können. Dieser Messwert zählt die Anzahl der Fälle, in denen Pub/Sub Anfragen mit Bestätigungs-IDs (ModifyAckDeadline- oder acknowledgment-Anfrage) nicht verarbeiten kann. Die Gründe für den Fehler können server- oder clientseitig sein. Wenn beispielsweise die Speicherebene, die zum Speichern der Informationen zur genau einmal erfolgenden Übermittlung verwendet wird, nicht verfügbar ist, handelt es sich um ein serverbasiertes Ereignis. Wenn der Client versucht, eine Nachricht mit einer ungültigen Bestätigungs-ID zu bestätigen, handelt es sich um ein clientbasiertes Ereignis.

Messwert

subscription/exactly_once_warning_count erfasst Ereignisse, die möglicherweise zu tatsächlichen erneuten Übermittlungen führen. Je nach Clientverhalten kann es zu vielen unnötigen Daten kommen. Beispiel: Wiederholte acknowledgment- oder ModifyAckDeadline-Anfragen mit ungültigen Bestätigungs-IDs erhöhen den Messwert wiederholt.

Die folgenden Messwerte sind ebenfalls hilfreich, um das Kundenverhalten zu verstehen:

  • Der Messwert subscription/expired_ack_deadlines_count gibt die Anzahl der abgelaufenen Bestätigungs-IDs an. Abgelaufene Bestätigungs-IDs können sowohl bei ModifyAckDeadline- als auch bei acknowledgment-Anfragen zu Fehlern führen.

  • Mit dem Messwert service.serviceruntime.googleapis.com/api/request_count können Fehler bei ModifyAckDeadline- oder acknowledgment-Anfragen erfasst werden, wenn die Anfragen Google Cloud erreichen, aber nicht Pub/Sub. Es gibt Fehler, die mit diesem Messwert nicht erfasst werden, z. B. wenn die Verbindung von Clients zu Google Cloud unterbrochen wird.

In den meisten Fällen von Fehlerereignissen, die wiederholt werden können, wiederholen unterstützte Clientbibliotheken den Antrag automatisch.

Kontingente

Für Abos mit genau einmal zugestellter Zustellung gelten zusätzliche Kontingentanforderungen. Diese Kontingente gelten für:

  • Anzahl der Nachrichten, die über Abos mit der Zustellung genau einmal pro Region verbraucht wurden.
  • Anzahl der Nachrichten, die bei Verwendung von Abos mit aktivierter „Genau einmal“-Zustellung pro Region bestätigt oder deren Frist verlängert wurde.

Weitere Informationen zu diesen Kontingenten finden Sie in der Tabelle im Thema Kontingente.

Genau einmal zugestellt und geordnete Abos

Pub/Sub unterstützt die genau einmalige Zustellung mit sortierter Zustellung.

Wenn Sie die Sortierung mit der genau einmal erfolgenden Zustellung verwenden, erwartet Pub/Sub, dass die Bestätigungen in der richtigen Reihenfolge sind. Wenn die Bestätigungen nicht in der richtigen Reihenfolge sind, schlägt der Dienst die Anfragen mit temporären Fehlern fehl. Wenn die Bestätigungsfrist abläuft, bevor eine ordnungsgemäße Bestätigung für die Zustellung erfolgt, erhält der Client eine erneute Zustellung der Nachricht. Wenn Sie die Sortierung mit der Zustellung genau einmal verwenden, ist der Clientdurchsatz daher auf etwa tausend Nachrichten pro Sekunde begrenzt.

Genau einmal zugestellt und Push-Abos

Pub/Sub unterstützt die genau einmalige Zustellung nur mit Pull-Abos.

Clients, die Nachrichten von den Push-Abos nutzen, bestätigen die Nachrichten, indem sie auf die Push-Anfragen mit einer Erfolgsantwort antworten. Clients wissen jedoch nicht, ob das Pub/Sub-Abo die Antwort erhalten und verarbeitet hat. Das unterscheidet sich von Pull-Abos, bei denen Bestätigungsanfragen von den Clients initiiert werden und das Pub/Sub-Abo antwortet, wenn die Anfrage erfolgreich verarbeitet wurde. Aus diesem Grund eignen sich die genau einmal-Semantiken nicht gut für Push-Abos.

Wichtige Informationen

  • Wenn beim Erstellen eines Abos keine Frist für die Bestätigung angegeben wird, gilt für Abos mit aktivierter Zustellung genau einmal eine Standardfrist von 60 Sekunden.

  • Längere Standardfristen für die Bestätigung helfen, eine erneute Zustellung aufgrund von Netzwerkereignissen zu vermeiden. Bei unterstützten Clientbibliotheken wird die Standardfrist für die Bestätigung von Abos nicht verwendet.

  • Bei Abos mit der genau einmaligen Zustellung ist die Latenz zwischen Veröffentlichung und Abo deutlich höher als bei regulären Abos.

  • Wenn Sie einen hohen Durchsatz benötigen, müssen Ihre Clients für die „Genau einmal“-Auslieferung auch Streaming-Pull verwenden.

  • Ein Abo kann aufgrund von Duplikaten auf der Veröffentlichungsseite auch dann mehrere Kopien derselben Nachricht erhalten, wenn die Zustellung genau einmal aktiviert ist. Duplikate auf Veröffentlichungsseite können auf mehrere eindeutige Veröffentlichungswiederholungen durch den Veröffentlichungsclient oder den Pub/Sub-Dienst zurückzuführen sein. Mehrere eindeutige Veröffentlichungen durch den Publish-Client bei mehreren Versuchen führen zu erneuten Übermittlungen mit unterschiedlichen Nachrichten-IDs. Mehrere eindeutige Veröffentlichungen durch den Pub/Sub-Dienst, um auf eine Client-Veröffentlichungsanfrage zu reagieren, führen zu erneuten Übermittlungen mit denselben Nachrichten-IDs.

  • Sie können fehlgeschlagene Abfragen in subscription/exactly_once_warning_count wiederholen. Die unterstützten Clientbibliotheken wiederholen diese automatisch. Fehler im Zusammenhang mit ungültigen Bestätigungs-IDs können jedoch nicht wiederholt werden.