How does one programmatically subscribe an SQS queue to an SNS topic in Go?

时间:2019-01-15 18:29:30

标签: aws-sdk-go

Here is what I tried, using version 53eb8b070e9a5067829fd029539966181632032a of aws-sdk-go.

// main.go
package main

import (
    "errors"
    "fmt"
    "log"
    "net/http"

    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/sns"
    "github.com/aws/aws-sdk-go/service/sqs"
)

func main() {
    if err := makeTopicAndQueue(); err != nil {
        log.Fatalf("aws-sns-sqs: %v", err)
    }
}

func makeTopicAndQueue() error {
    sess, err := session.NewSession(&aws.Config{
        HTTPClient:  &http.Client{},
        Region:      aws.String("us-east-2"),
        Credentials: nil,
        MaxRetries:  aws.Int(0),
    })

    log.Printf("Creating an SNS topic.")
    snsClient := sns.New(sess, &aws.Config{})
    topicName := "test-topic"
    out, err := snsClient.CreateTopic(&sns.CreateTopicInput{Name: aws.String(topicName)})
    if err != nil {
        return fmt.Errorf(`creating topic "%s": %v`, topicName, err)
    }
    defer snsClient.DeleteTopic(&sns.DeleteTopicInput{TopicArn: out.TopicArn})

    log.Printf("Creating an SQS queue.")
    sqsClient := sqs.New(sess, &aws.Config{})
    subName := "test-subscription"
    out2, err := sqsClient.CreateQueue(&sqs.CreateQueueInput{QueueName: aws.String(subName)})
    if err != nil {
        return fmt.Errorf(`creating subscription queue "%s": %v`, subName, err)
    }

    log.Printf("Getting queue ARN.")
    out3, err := sqsClient.GetQueueAttributes(&sqs.GetQueueAttributesInput{
        QueueUrl:       out2.QueueUrl,
        AttributeNames: []*string{aws.String("QueueArn")},
    })
    if err != nil {
        return fmt.Errorf("getting queue ARN for %s: %v", *out2.QueueUrl, err)
    }
    qARN := out3.Attributes["QueueArn"]

    log.Printf("Subscribing the queue to the topic.")
    _, err = snsClient.Subscribe(&sns.SubscribeInput{
        TopicArn: out.TopicArn,
        Endpoint: qARN,
        Protocol: aws.String("sqs"),
    })
    if err != nil {
        return fmt.Errorf("subscribing: %v", err)
    }

    log.Printf("Getting the confirmation token from the queue.")
    out4, err := sqsClient.ReceiveMessage(&sqs.ReceiveMessageInput{
        QueueUrl: out2.QueueUrl,
    })
    if err != nil {
        return fmt.Errorf("receiving subscription confirmation message from queue: %v", err)
    }
    ms := out4.Messages
    var token *string
    switch len(ms) {
    case 0:
        return errors.New("no subscription confirmation message found in queue")
    case 1:
        m := ms[0]
        token = m.Body
    default:
        return fmt.Errorf("%d messages found in queue, want exactly 1", len(ms))
    }

    log.Printf("Using the token to finish subscribing.")
    _, err = snsClient.ConfirmSubscription(&sns.ConfirmSubscriptionInput{
        TopicArn: out.TopicArn,
        Token:    token,
    })
    if err != nil {
        return fmt.Errorf("confirming subscription: %v", err)
    }
    sqsClient.DeleteQueue(&sqs.DeleteQueueInput{QueueUrl: out2.QueueUrl})

    return nil
}

I expected it to get to the end but it failed with this output:

[ ~/src/aws-sqs-issue ] go run main.go
2019/01/15 09:31:19 Creating an SNS topic.
2019/01/15 09:31:19 Creating an SQS queue.
2019/01/15 09:31:20 Getting queue ARN.
2019/01/15 09:31:20 Subscribing the queue to the topic.
2019/01/15 09:31:21 Getting the confirmation token from the queue.
2019/01/15 09:31:21 aws-sns-sqs: no subscription confirmation message found in queue

Am I doing something wrong or is this a bug in the SDK?

I'm not sure what else to say about this. Here is some additional verbiage to somehow get the warning about the post being mostly code to go away. It's best to stop reading at this point because all the rest of this is bound to make for boring reading. I don't know much much longer I can keep on making up nonsense to satisfy this silly algorithm. Why don't they allow a simple post that contains a lot of code? I have no idea. Ah well. There is an upside down gopher on my desk. I think it was intentional. Due to the poor critter's anatomy, he's doing more of an eyeball-stand than a head-stand. My desk plant didn't hold up too well over the holidays. Better give it some water. Wowee, this thing really wants an awful lot of words. Well, I aim to please. If I keep going, will I accidentally output some Shakespeare? Well, it's over, thank the Bard.

1 个答案:

答案 0 :(得分:1)

这个很老了,但是解决这个问题的诀窍是

  

要使Amazon SNS主题能够将消息发送到队列,您必须在队列上设置一个策略,该策略允许Amazon SNS主题执行sqs:SendMessage操作。 See more

要使用当前版本的V1 SDK进行此操作,在创建队列时,您必须手动将策略定义为队列属性,以允许SNS主题将消息发送到SQS队列。

以下是示例代码:

    queueARN := fmt.Sprintf("arn:aws:sqs:%s:%s:%s", "us-east-1", "xxx", "my-queue")
    topicARN := fmt.Sprintf("arn:aws:sns:%s:%s:%s", "us-east-1", "xxx", "my-topic")
    _, err := b.sqs.CreateQueue(&sqs.CreateQueueInput{
        QueueName: aws.String("my-queue"),
        Attributes: map[string]*string{
            "Policy": aws.String(fmt.Sprintf(`{
                "Version": "2012-10-17",
                "Statement": [
                    {
                        "Sid": "SNSTopicSendMessage",
                        "Effect": "Allow",
                        "Principal": "*",
                        "Action": "SQS:SendMessage",
                        "Resource": "%s",
                        "Condition": {
                            "ArnEquals": {
                                "aws:SourceArn": "%s"
                            }
                        }
                    }
                ]
            }`, queueARN, b.eventsTopicARN)),
        },
    })
    if err != nil {
        return err
    }