简体   繁体   English

如何通过转发到死信主题来限制 Google Pub/Sub 交付尝试?

[英]How to limit Google Pub/Sub delivery attempts by forwarding to a dead-letter topic?

I'm trying to configure a Pub/Sub subscription with a dead-letter topic (cf. https://cloud.google.com/pubsub/docs/dead-letter-topics ) in order to limit the number of times the message gets redelivered when it gets nack'd.我正在尝试使用死信主题(参见https://cloud.google.com/pubsub/docs/dead-letter-topics )配置 Pub/Sub 订阅,以限制消息的次数收到后会重新交付。 To this end, I've created the following example program:为此,我创建了以下示例程序:

package main

import (
    "context"
    "flag"
    "fmt"
    "log"
    "os"
    "time"

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

const (
    topicID           = "my-topic"
    deadLetterTopicID = "my-dead-letter-topic"
    subscriptionID    = "my-subscription"
)

var (
    pubsubEmulatorHost string
    projectID          string
)

func main() {
    flag.StringVar(&pubsubEmulatorHost, "pubsubEmulatorHost", "", "Pub/Sub emulator host (e.g. localhost:8085)")
    flag.StringVar(&projectID, "projectID", "my-project", "Google Project ID")
    flag.Parse()

    if pubsubEmulatorHost != "" {
        os.Setenv("PUBSUB_EMULATOR_HOST", pubsubEmulatorHost)
        defer os.Unsetenv("PUBSUB_EMULATOR_HOST")
    }

    client, err := pubsub.NewClient(context.Background(), projectID)
    if err != nil {
        log.Fatalf("NewClient: %v", err)
    }

    topic, err := client.CreateTopic(context.Background(), topicID)
    if err != nil {
        if status.Code(err) == codes.AlreadyExists {
            topic = client.Topic(topicID)
            log.Printf("Topic %s already exists", topicID)
        } else {
            log.Fatalf("CreateTopic: %v", err)
        }
    }
    defer func() {
        topic.Stop()
        if err := topic.Delete(context.Background()); err != nil {
            log.Fatalf("Delete topic: %v", err)
        }
    }()

    deadLetterTopic, err := client.CreateTopic(context.Background(), deadLetterTopicID)
    if err != nil {
        if status.Code(err) == codes.AlreadyExists {
            deadLetterTopic = client.Topic(deadLetterTopicID)
            log.Printf("Topic %s already exists", deadLetterTopicID)
        } else {
            log.Fatalf("CreateTopic: %v", err)
        }
    }
    defer func() {
        deadLetterTopic.Stop()
        if err := deadLetterTopic.Delete(context.Background()); err != nil {
            log.Fatalf("Delete dead-letter topic: %v", err)
        }
    }()

    sub, err := client.CreateSubscription(context.Background(), subscriptionID, pubsub.SubscriptionConfig{
        Topic: topic,
        DeadLetterPolicy: &pubsub.DeadLetterPolicy{
            DeadLetterTopic:     fmt.Sprintf("projects/%s/topics/%s", projectID, deadLetterTopicID),
            MaxDeliveryAttempts: 5,
        },
    })
    if err != nil {
        log.Fatalf("CreateSubscription: %v", err)
    }
    defer func() {
        if err := sub.Delete(context.Background()); err != nil {
            log.Fatalf("Delete subscription: %v", err)
        }
    }()

    go func() {
        sub.Receive(context.Background(), func(ctx context.Context, msg *pubsub.Message) {
            log.Printf("Got message %q upon delivery attempt %d", msg.Data, msg.DeliveryAttempt)
            msg.Nack()
        })
    }()

    result := topic.Publish(context.Background(), &pubsub.Message{Data: []byte("Hello, world!")})
    messageID, err := result.Get(context.Background())
    if err != nil {
        log.Fatalf("Get message ID of publish call: %v", err)
    }
    log.Printf("Published message with ID %s", messageID)
    time.Sleep(20 * time.Second)
}

The script runs in two modes, one with a genuine Pub/Sub project (called my-project here) and one using the GCloud Pub/Sub emulator by setting the PUBSUB_EMULATOR_HOST environment variable.该脚本以两种模式运行,一种使用真正的 Pub/Sub 项目(此处称为my-project ),另一种通过设置PUBSUB_EMULATOR_HOST环境变量使用GCloud Pub/Sub 模拟器 I would expect, given that the subscription's DeadLetterPolicy has MaxDeliveryAttempts set to 5, that the nack'd Pub/Sub message is delivered approximately 5 times (the docs indicate that this is a best effort).我希望,鉴于订阅的DeadLetterPolicyMaxDeliveryAttempts设置为 5,nack'd Pub/Sub 消息将被传递大约 5 次(文档表明这是尽最大努力)。 If I run the script on a real Pub/Sub project, however, I get the following output:但是,如果我在真正的 Pub/Sub 项目上运行脚本,我会得到以下 output:

> go run main.go
2020/06/22 23:59:37 Published message with ID 1294186248588871
2020/06/22 23:59:38 Got message "Hello, world!" upon delivery attempt 824637866440
2020/06/22 23:59:40 Got message "Hello, world!" upon delivery attempt 824634417896
2020/06/22 23:59:41 Got message "Hello, world!" upon delivery attempt 824634418592
2020/06/22 23:59:43 Got message "Hello, world!" upon delivery attempt 824637866928
2020/06/22 23:59:44 Got message "Hello, world!" upon delivery attempt 824638981864
2020/06/22 23:59:45 Got message "Hello, world!" upon delivery attempt 824640667960
2020/06/22 23:59:47 Got message "Hello, world!" upon delivery attempt 824634418712
2020/06/22 23:59:49 Got message "Hello, world!" upon delivery attempt 824638982160
2020/06/22 23:59:50 Got message "Hello, world!" upon delivery attempt 824640667760
2020/06/22 23:59:51 Got message "Hello, world!" upon delivery attempt 824634418000
2020/06/22 23:59:52 Got message "Hello, world!" upon delivery attempt 824633942168
2020/06/22 23:59:53 Got message "Hello, world!" upon delivery attempt 824633942712
2020/06/22 23:59:53 Got message "Hello, world!" upon delivery attempt 824640668296
2020/06/22 23:59:54 Got message "Hello, world!" upon delivery attempt 824637448352
2020/06/22 23:59:55 Got message "Hello, world!" upon delivery attempt 824633943336
2020/06/22 23:59:55 Got message "Hello, world!" upon delivery attempt 824633943448
2020/06/22 23:59:56 Got message "Hello, world!" upon delivery attempt 824633943560
2020/06/22 23:59:57 Got message "Hello, world!" upon delivery attempt 824638259688
2020/06/22 23:59:57 Got message "Hello, world!" upon delivery attempt 824637448752

In other words, the nack'd message is delivered 19 times, nowhere near the 5 times I would expect.换句话说,nack 的消息被传递了 19 次,与我预期的 5 次相去甚远。 If I run the program using the Pub/Sub emulator, I get that the delivery attempt is always 0:如果我使用 Pub/Sub 模拟器运行程序,我会发现交付尝试始终为 0:

> go run main.go --pubsubEmulatorHost=localhost:8085
2020/06/23 00:00:54 Published message with ID 4
2020/06/23 00:00:54 Got message "Hello, world!" upon delivery attempt 0
2020/06/23 00:00:54 Got message "Hello, world!" upon delivery attempt 0
2020/06/23 00:00:54 Got message "Hello, world!" upon delivery attempt 0
2020/06/23 00:00:54 Got message "Hello, world!" upon delivery attempt 0
2020/06/23 00:00:54 Got message "Hello, world!" upon delivery attempt 0
2020/06/23 00:00:54 Got message "Hello, world!" upon delivery attempt 0
2020/06/23 00:00:54 Got message "Hello, world!" upon delivery attempt 0
2020/06/23 00:00:54 Got message "Hello, world!" upon delivery attempt 0
2020/06/23 00:00:54 Got message "Hello, world!" upon delivery attempt 0
2020/06/23 00:00:54 Got message "Hello, world!" upon delivery attempt 0
2020/06/23 00:00:55 Got message "Hello, world!" upon delivery attempt 0
2020/06/23 00:00:55 Got message "Hello, world!" upon delivery attempt 0
2020/06/23 00:00:55 Got message "Hello, world!" upon delivery attempt 0
2020/06/23 00:00:55 Got message "Hello, world!" upon delivery attempt 0
2020/06/23 00:00:55 Got message "Hello, world!" upon delivery attempt 0
2020/06/23 00:00:55 Got message "Hello, world!" upon delivery attempt 0
2020/06/23 00:00:55 Got message "Hello, world!" upon delivery attempt 0
2020/06/23 00:00:55 Got message "Hello, world!" upon delivery attempt 0
2020/06/23 00:00:55 Got message "Hello, world!" upon delivery attempt 0
2020/06/23 00:00:55 Got message "Hello, world!" upon delivery attempt 0
2020/06/23 00:00:56 Got message "Hello, world!" upon delivery attempt 0
...

Here the output is truncated for brevity, but the message is printed about ~200 times (10 times per second for 20 seconds), again far above the 5 times I would expect.为简洁起见,此处 output 被截断,但消息打印了大约 200 次(每秒 10 次,持续 20 秒),再次远高于我预期的 5 次。

Is the MaxDeliveryAttempts field of the DeadLetterPolicy not supposed to limit the number of delivery attempts for nack'd messages? DeadLetterPolicyMaxDeliveryAttempts字段是否不应该限制 nack 消息的传递尝试次数? And why is the DeliveryAttempt field such a weird sequence of integers rather than one that simply increments by 1 each time (cf. https://pkg.go.dev/cloud.google.com/go/pubsub?tab=doc#Message )?为什么DeliveryAttempt字段是一个如此奇怪的整数序列,而不是每次简单地增加 1 的整数序列(参见https://pkg.go.dev/cloud.google.com/go/pubsub?tab=doc#Message )?

In order to further contribuite the community I am posting this answer from what I mentioned in the comment section.为了进一步为社区做出贡献,我根据我在评论部分中提到的内容发布了这个答案。

The issue you described generally happens when you do not give the required permissions ( here under Dead Letter Queue Options) so PubSub can publish to your dead letter topic or subscribe to your subscription.您描述的问题通常发生在您未提供所需权限( 此处在死信队列选项下)时,因此 PubSub 可以发布到您的死信主题或订阅您的订阅。 Also, I must point that if writing to the dead letter queue topic fails, PubSub will continue to deliver the message to your subscriber.另外,我必须指出,如果写入死信队列主题失败,PubSub 将继续将消息传递给您的订阅者。

In order to give the necessary permissions, you can use the following commands in your shell environment:为了提供必要的权限,您可以在 shell 环境中使用以下命令:

PUBSUB_SERVICE_ACCOUNT="service-${PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com"

gcloud pubsub topics add-iam-policy-binding <dead letter topic> \  --member="serviceAccount:${PUBSUB_SERVICE_ACCOUNT}"\  --role='roles/pubsub.publisher'

gcloud pubsub subscriptions add-iam-policy-binding <subscription with dead letter queue> \  --member="serviceAccount:${PUBSUB_SERVICE_ACCOUNT}"\  --role='roles/pubsub.subscriber'

Also, I would like to add @Mahesh Gattani coment, which mentions that the emulator currently does not support dead letter topics.另外,我想添加@Mahesh Gattani 评论,其中提到模拟器目前不支持死信主题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用监听服务实现发布/订阅谷歌 - How implement pub/sub google with listen serve 通过goroutine异步发布到google pub sub - Publishing to google pub sub asynchronously through goroutine Google Pub/Sub 的 RetryPolicy 中配置的指数退避如何工作? - How does the exponential backoff configured in Google Pub/Sub's RetryPolicy work? 如何使用 protobuf 二进制文件在 PUB/SUB ( ZeroMQ ) 中进行过滤? - How to filter in PUB/SUB ( ZeroMQ ) with protobuf binaries? 使用 Go 读取来自 Google Pub Sub 的所有可用消息 - Reading all the available messages from Google Pub Sub using Go 如何检查Cloud Pub / Sub模拟器是否已启动并正在运行? - How to check if Cloud Pub/Sub emulator is up and running? go和grpc如何解决pub-sub问题? - How to solve pub-sub problem in go and grpc? 水平自动缩放的 Kubernetes pod 未从 Google Cloud Pub/Sub 订阅中提取消息 - Horizontally Autoscaled Kubernetes pods not pulling messages from Google Cloud Pub/Sub subscription Google Pub/Sub 消息排序不起作用(或将延迟增加到 10 秒以上)? - Google Pub/Sub message ordering not working (or increasing latency to over 10 seconds)? ZeroMQ中的PUB / SUB模式不起作用 - PUB/SUB pattern in ZeroMQ not working
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM