Как программно подписать очередь SQS на тему SNS в Go? - PullRequest
0 голосов
/ 15 января 2019

Вот что я пробовал, используя версию 53eb8b070e9a5067829fd029539966181632032a из 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
}

Я ожидал, что он дойдет до конца, но не получится с таким выводом:

[ ~/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

Я что-то не так делаю или это ошибка в SDK?

Я не уверен, что еще сказать по этому поводу. Вот несколько дополнительных слов, чтобы как-то получить предупреждение о том, что сообщение - это в основном код, который нужно удалить. Лучше прекратить чтение на этом этапе, потому что все остальное обязательно для скучного чтения. Я не знаю намного дольше, я могу продолжать придумывать глупости, чтобы удовлетворить этот глупый алгоритм. Почему они не допускают простой пост, который содержит много кода? Я понятия не имею. Ах хорошо. На моем столе перевернутый суслик. Я думаю, что это было сделано намеренно. Из-за анатомии бедного твари, он делает больше подставку для глазного яблока, чем подставку для головы. Мой настольный завод не слишком хорошо держался в праздничные дни. Лучше дать ему немного воды. Вау, эта штука действительно хочет очень много слов. Ну, я стремлюсь, пожалуйста. Если я продолжу, я случайно выведу Шекспира? Ну, все, спасибо Барду.

1 Ответ

0 голосов
/ 03 июня 2019

Это довольно старый, но вот хитрость, чтобы решить это:

Чтобы тема Amazon SNS могла отправлять сообщения в очередь, необходимо установить в очереди политику, которая позволяет разделу Amazon SNS выполнять действие sqs: SendMessage. Подробнее

Чтобы сделать это, используя текущую версию 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
    }
...