デッドレター トピック

サブスクライバーは、さまざまな理由でメッセージを処理できない場合があります。たとえば、メッセージの処理に必要なデータを取得する際に一時的な問題が発生している可能性があります。サブスクライバーが想定していない形式のメッセージが含まれている場合もあります。

サブスクライバーが確認応答できない配信不能メッセージを管理するために、Pub/Sub はこれらのメッセージをデッドレター トピック(デッドレター キューとも呼ばれます)に転送できます。

始める前に

  • デッドレター トピック構成のトピックを作成します。

    また、このページの手順をすべて実行する場合は、後続のステップでトピックを作成できます。

必要なロール

トピックとサブスクリプションの管理に必要な権限を取得するには、プロジェクトに対する Pub/Sub 編集者 roles/pubsub.editor)の IAM ロールを付与するように管理者に依頼してください。ロールの付与については、プロジェクト、フォルダ、組織に対するアクセス権の管理をご覧ください。

必要な権限は、カスタムロールや他の事前定義ロールから取得することもできます。

アクセス制御は、プロジェクト レベルと個々のリソースレベルで構成できます。あるプロジェクトにサブスクリプションを作成し、別のプロジェクトにあるトピックにアタッチできます。プロジェクトごとに必要な権限があることを確認します。

デッドレター トピックの仕組み

サブスクライバー アプリケーションがメッセージを確認応答できない場合、Pub/Sub は確認応答期限に達するか、メッセージの有効期限が切れるまで配信を再試行します。構成された配信試行回数に達すると、Pub/Sub は配信不能メッセージをデッドレター トピックに転送できます。

Pub/Sub が配信不能メッセージを転送すると、元のメッセージが新しいメッセージでラップされ、送信元サブスクリプションを識別する属性が追加されます。メッセージは、指定されたデッドレター トピックに送信されます。デッドレター トピックにアタッチされた別のサブスクリプションは、転送されたメッセージを受信して分析し、オフラインでデバッグできます。

配信の最大試行回数の計算方法

Pub/Sub は、デッドレター トピックが正しく構成され、正しい IAM 権限が含まれている場合にのみ、配信の試行回数をカウントします。

Pub/Sub では、ベスト エフォート方式でメッセージが転送されるため、配信の最大試行回数には誤差が生じる場合があります。サービスは、構成された試行回数よりも少ない回数でメッセージを転送したり、転送前に数回配信を試行したりする場合があります。

特に、非アクティブなサブスクライバーを持つ pull サブスクリプションの場合、メッセージの配信試行回数はゼロにリセットされることもあります。その結果、構成された最大配信試行回数を超えて、サブスクライバー クライアントにメッセージが配信される可能性があります。

デッドレター トピックのプロパティ

デッドレター トピックには、次のサブスクリプション プロパティを設定できます。

  • 配信試行回数の上限: Pub/Sub が特定のメッセージに対して行う配信の試行回数を示す数値。構成された配信試行回数内にサブスクライバー クライアントがメッセージを確認応答できない場合、メッセージはデッドレター トピックに転送されます。

    • デフォルト値 = 5
    • 最大値 = 100
    • 最小値 = 5
  • デッドレター トピックを含むプロジェクト: デッドレター トピックがサブスクリプションとは異なるプロジェクトにある場合、そのデッドレター トピックがあるプロジェクトを指定する必要があります。サブスクリプションが接続されているトピックとは異なるトピックに、デッドレター トピックを設定します。

デッドレター トピックを構成する

次の手順では、デッドレター トピックを使用するワークフローについて説明します。

  1. トピックを作成します(デッドレター トピックとして使用するため)。

  2. デッドレター トピックのサブスクリプションを作成します。

  3. サブスクリプションでデッド レタリングを有効にします。

  4. 先ほど作成したトピックをサブスクリプションに関連付けます。

  5. デッドレター トピックを使用するために必要なロールを Pub/Sub サービス アカウントに付与します。

デッドレター トピックで使用するトピックを作成する

サブスクリプションに使用するトピックをすでに作成している場合は、この手順をスキップできます。

  1. Google Cloud コンソールで、[トピック] ページに移動します。

    [トピック] に移動

  2. [トピックを作成] をクリックします。

  3. トピック ID を入力します(例: my-test-topic)。

  4. デフォルトのサブスクリプションのオプションを保持し、[作成] をクリックします。

サブスクリプションにデッドレター トピックを設定する

デッドレター トピックは、新しいサブスクリプションまたは既存のサブスクリプションに設定できます。

新しいサブスクリプションにデッドレター トピックを設定する

Google Cloud コンソール、Google Cloud CLI、クライアント ライブラリ、または Pub/Sub API を使用して、サブスクリプションを作成してデッドレター トピックを設定できます。

コンソール

サブスクリプションを作成してデッドレター トピックを設定するには、次の手順を実行します。

  1. Google Cloud コンソールで、[サブスクリプション] ページに移動します。

    [サブスクリプション] に移動

  2. [サブスクリプションを作成] をクリックします。

  3. [サブスクリプション ID] を入力します。

  4. 定期購入で使用するトピックを選択します。サブスクリプションがトピックからメッセージを受信します。これはデッドレター トピックではありません。これは次のステップで選択します。

  5. [配信エラー]セクションで、[配信エラーを有効にする]を選択します。

  6. プルダウン メニューからデッドレター トピックを選択します。

    選択したデッドレター トピックにサブスクリプションがない場合、サブスクリプションを作成するように求められます。

  7. [配信の最大試行回数] フィールドで、5〜100 の整数を指定します。

  8. [作成] をクリックします。

  9. [詳細パネル] をクリックして、実行可能なアクション アイテムを確認します。いずれかの項目にエラーアイコン が表示されている場合は、アクション アイテムをクリックして問題を解決します。

    [デッド レタリング] タブにアクション アイテムが表示されている。

gcloud

サブスクリプションを作成してデッドレター トピックを設定するには、gcloud pubsub subscriptions create コマンドを使用します。

gcloud pubsub subscriptions create subscription-id \
  --topic=topic-id \
  --dead-letter-topic=dead-letter-topic-name \
  [--max-delivery-attempts=max-delivery-attempts] \
  [--dead-letter-topic-project=dead-letter-topic-project]

C++

このサンプルを試す前に、クイックスタート: クライアント ライブラリの使用の C++ の設定手順を実施してください。詳細については、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,
   std::string const& dead_letter_topic_id,
   int dead_letter_delivery_attempts) {
  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.mutable_dead_letter_policy()->set_dead_letter_topic(
      pubsub::Topic(project_id, dead_letter_topic_id).FullName());
  request.mutable_dead_letter_policy()->set_max_delivery_attempts(
      dead_letter_delivery_attempts);
  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";

  std::cout << "It will forward dead letter messages to: "
            << sub->dead_letter_policy().dead_letter_topic() << "\n";

  std::cout << "After " << sub->dead_letter_policy().max_delivery_attempts()
            << " delivery attempts.\n";
}

C#

このサンプルを試す前に、クイックスタート: クライアント ライブラリの使用の C# の設定手順を実施してください。詳細については、Pub/Sub C# API リファレンス ドキュメントをご覧ください。


using Google.Cloud.PubSub.V1;
using System;

public class CreateSubscriptionWithDeadLetterPolicySample
{
    public Subscription CreateSubscriptionWithDeadLetterPolicy(string projectId, string topicId, string subscriptionId, string deadLetterTopicId)
    {
        SubscriberServiceApiClient subscriber = SubscriberServiceApiClient.Create();
        // This is the subscription you want to create with a dead letter policy.
        var subscriptionName = SubscriptionName.FromProjectSubscription(projectId, subscriptionId);
        // This is an existing topic that you want to attach the subscription with dead letter policy to.
        var topicName = TopicName.FromProjectTopic(projectId, topicId);
        // This is an existing topic that the subscription with dead letter policy forwards dead letter messages to.
        var deadLetterTopic = TopicName.FromProjectTopic(projectId, deadLetterTopicId).ToString();
        var subscriptionRequest = new Subscription
        {
            SubscriptionName = subscriptionName,
            TopicAsTopicName = topicName,
            DeadLetterPolicy = new DeadLetterPolicy
            {
                DeadLetterTopic = deadLetterTopic,
                // The maximum number of times that the service attempts to deliver a
                // message before forwarding it to the dead letter topic. Must be [5-100].
                MaxDeliveryAttempts = 10
            },
            AckDeadlineSeconds = 30
        };

        var subscription = subscriber.CreateSubscription(subscriptionRequest);
        Console.WriteLine("Created subscription: " + subscription.SubscriptionName.SubscriptionId);
        Console.WriteLine($"It will forward dead letter messages to: {subscription.DeadLetterPolicy.DeadLetterTopic}");
        Console.WriteLine($"After {subscription.DeadLetterPolicy.MaxDeliveryAttempts} delivery attempts.");
        // Remember to attach a subscription to the dead letter topic because
        // messages published to a topic with no subscriptions are lost.
        return subscription;
    }
}

Go

次のサンプルでは、Go Pub/Sub クライアント ライブラリのメジャー バージョン(v2)を使用しています。v1 ライブラリをまだ使用している場合は、v2 への移行ガイドをご覧ください。v1 コードサンプルの一覧については、 非推奨のコードサンプルをご覧ください。

このサンプルを試す前に、クイックスタート: クライアント ライブラリの使用の Go の設定手順を実施してください。詳細については、Pub/Sub Go API のリファレンス ドキュメントをご覧ください。

import (
	"context"
	"fmt"
	"io"

	"cloud.google.com/go/pubsub/v2"
	"cloud.google.com/go/pubsub/v2/apiv1/pubsubpb"
)

// createSubWithDeadLetter creates a subscription with a dead letter policy.
func createSubWithDeadLetter(w io.Writer, projectID, topic, subscription, fullyQualifiedDeadLetterTopic string) error {
	// projectID := "my-project-id"
	// topic := "projects/my-project-id/topics/my-topic"
	// subscription := "projects/my-project-id/subscriptions/my-sub"
	// fullyQualifiedDeadLetterTopic := "projects/my-project-id/topics/my-dead-letter-topic"
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("pubsub.NewClient: %w", err)
	}
	defer client.Close()

	_, err = client.SubscriptionAdminClient.CreateSubscription(ctx, &pubsubpb.Subscription{
		Name:  subscription,
		Topic: topic,
		DeadLetterPolicy: &pubsubpb.DeadLetterPolicy{
			DeadLetterTopic:     fullyQualifiedDeadLetterTopic,
			MaxDeliveryAttempts: 10,
		},
	})
	if err != nil {
		return fmt.Errorf("CreateSubscription: %w", err)
	}
	fmt.Fprintf(w, "Created subscription with dead letter topic: (%s)\n", fullyQualifiedDeadLetterTopic)
	fmt.Fprintln(w, "To process dead letter messages, remember to add a subscription to your dead letter topic.")
	return nil
}

Java

このサンプルを試す前に、クイックスタート: クライアント ライブラリの使用の Java の設定手順を実施してください。詳細については、Pub/Sub Java API リファレンス ドキュメントをご覧ください。

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

public class CreateSubscriptionWithDeadLetterPolicyExample {

  public static void main(String... args) throws Exception {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "your-project-id";
    // This is the subscription you want to create with a dead letter policy.
    String subscriptionId = "your-subscription-id";
    // This is an existing topic that you want to attach the subscription with dead letter policy
    // to.
    String topicId = "your-topic-id";
    // This is an existing topic that the subscription with dead letter policy forwards dead letter
    // messages to.
    String deadLetterTopicId = "your-dead-letter-topic-id";

    CreateSubscriptionWithDeadLetterPolicyExample.createSubscriptionWithDeadLetterPolicyExample(
        projectId, subscriptionId, topicId, deadLetterTopicId);
  }

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

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

      DeadLetterPolicy deadLetterPolicy =
          DeadLetterPolicy.newBuilder()
              .setDeadLetterTopic(deadLetterTopicName.toString())
              // The maximum number of times that the service attempts to deliver a
              // message before forwarding it to the dead letter topic. Must be [5-100].
              .setMaxDeliveryAttempts(10)
              .build();

      Subscription request =
          Subscription.newBuilder()
              .setName(subscriptionName.toString())
              .setTopic(topicName.toString())
              .setDeadLetterPolicy(deadLetterPolicy)
              .build();

      Subscription subscription = subscriptionAdminClient.createSubscription(request);

      System.out.println("Created subscription: " + subscription.getName());
      System.out.println(
          "It will forward dead letter messages to: "
              + subscription.getDeadLetterPolicy().getDeadLetterTopic());
      System.out.println(
          "After "
              + subscription.getDeadLetterPolicy().getMaxDeliveryAttempts()
              + " delivery attempts.");
      // Remember to attach a subscription to the dead letter topic because
      // messages published to a topic with no subscriptions are lost.
    }
  }
}

Node.js

このサンプルを試す前に、クイックスタート: クライアント ライブラリの使用の Node.js の設定手順を実施してください。詳細については、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';
// const deadLetterTopicNameOrId = 'YOUR_DEAD_LETTER_TOPIC_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 createSubscriptionWithDeadLetterPolicy(
  topicNameOrId,
  subscriptionNameOrId,
  deadLetterTopicNameOrId,
) {
  // Creates a new subscription
  const options = {
    deadLetterPolicy: {
      deadLetterTopic: pubSubClient.topic(deadLetterTopicNameOrId).name,
      maxDeliveryAttempts: 10,
    },
  };
  await pubSubClient
    .topic(topicNameOrId)
    .createSubscription(subscriptionNameOrId, options);
  console.log(
    `Created subscription ${subscriptionNameOrId} with dead letter topic ${deadLetterTopicNameOrId}.`,
  );
  console.log(
    'To process dead letter messages, remember to add a subscription to your dead letter topic.',
  );
}

Node.js

このサンプルを試す前に、クイックスタート: クライアント ライブラリの使用の Node.js の設定手順を実施してください。詳細については、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';
// const deadLetterTopicNameOrId = 'YOUR_DEAD_LETTER_TOPIC_NAME_OR_ID';

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

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

async function createSubscriptionWithDeadLetterPolicy(
  topicNameOrId: string,
  subscriptionNameOrId: string,
  deadLetterTopicNameOrId: string,
) {
  // Creates a new subscription
  const options: CreateSubscriptionOptions = {
    deadLetterPolicy: {
      deadLetterTopic: pubSubClient.topic(deadLetterTopicNameOrId).name,
      maxDeliveryAttempts: 10,
    },
  };
  await pubSubClient
    .topic(topicNameOrId)
    .createSubscription(subscriptionNameOrId, options);
  console.log(
    `Created subscription ${subscriptionNameOrId} with dead letter topic ${deadLetterTopicNameOrId}.`,
  );
  console.log(
    'To process dead letter messages, remember to add a subscription to your dead letter topic.',
  );
}

PHP

このサンプルを試す前に、クイックスタート: クライアント ライブラリの使用の PHP の設定手順を実施してください。詳細については、