首页 > 解决方案 > SNS过滤器可以与订阅同时应用吗?

问题描述

假设一个 AWS SNS 主题。此主题的消息具有字符串类型的 MessageAttribute“IsTestMessage”。

使用 AWS 控制台,我添加了一个新的电子邮件订阅者。他们会收到一封确认电子邮件。确认后,他们将收到有关此主题的所有消息,包括测试消息。这不是故意的。

我想在他们确认之前应用一个过滤器,IsTestMessage: "false"例如让我说。

我可以在订阅创建时应用过滤器来避免这些不正确的交付吗?控制台中似乎没有办法这样做,但我愿意使用 CLI、SDK 等。

标签: amazon-sns

解决方案


通过 CLI,我一直遇到与@John Rotenstein 相同的错误:Error parsing parameter '--attributes': Expected: '=', received: '"'

无论我尝试了什么,它都没有接受它,所以我只能假设 sdk 的一部分被破坏了。

创建 SNS 主题、SQS 队列和添加订阅的完整 bash 示例:

# some params - SNS_ENDPOINT and SQS_ENDPOINT are for localstack - you probably don't need them
# in production
SQS_ENDPOINT="${SQS_ENDPOINT:-http://localhost:4566}"
SNS_ENDPOINT="${SNS_ENDPOINT:-http://localhost:4575}"
REGION=eu-west-1

# Create an SNS topic, "my-topic" and extract the ARN
MY_TOPIC_ARN=$(aws sns create-topic --name "my-topic" --endpoint-url=$SNS_ENDPOINT --region=$REGION --query TopicArn --output text)

# Create a SQS queue that will get messages from the SNS topic - extract the url
MY_QUEUE_URL=$(aws sqs create-queue --queue-name "my-queue" --endpoint-url=$SQS_ENDPOINT --region=$REGION --query QueueUrl --output text)

# Get the queue arn
MY_QUEUE_ARN=$(aws sqs get-queue-attributes --queue-url "$MY_QUEUE_URL" --endpoint-url=$SQS_ENDPOINT --attribute-names QueueArn --query Attributes --output text)

# Subscribe our sqs queue to our sns topic - extract the subscription arn
MY_SUBSCRIPTION_ARN=$(aws sns subscribe --topic-arn $MY_TOPIC_ARN --protocol sqs --notification-endpoint $MY_QUEUE_ARN --endpoint-url=$SNS_ENDPOINT --region=$REGION --attributes RawMessageDelivery=true --query SubscriptionArn --output text)

# Add a filter policy
aws sns set-subscription-attributes --subscription-arn $MY_SUBSCRIPTION_ARN --attribute-name FilterPolicy --attribute-value "{\"someKey\":[\"someValue\"]}" --endpoint-url=$SQS_ENDPOINT --region=$REGION

注意:这不涉及设置死信队列(一个用于订阅本身,一个用于 SQS 队列,具体取决于您使用它做什么),也不是您需要允许的策略SNS 向 SQS 等发送消息

云的形成

https://docs.aws.amazon.com/sns/latest/dg/SendMessageToSQS.cloudformation.html给出了一个同时创建一个订阅主题的例子:

"Resources": {
    "MySNSTopic": {
      "Type": "AWS::SNS::Topic",
      "Properties": {
        "Subscription": [{
            "Endpoint": {
              "Fn::GetAtt": ["MyQueue1", "Arn"]
            },
            "Protocol": "sqs"
          }]
      }
    },
    ...
}

我还没试过那个,所以我不能和它说话

无服务器

您也可以通过 Serverless 单独创建它们:

  Resources: 
    MyTopic:
      Type: "AWS::SNS::Topic"
      Properties:
        TopicName: ${self:custom.myTopicName}

    MyTopicQueue:
      Type: "AWS::SQS::Queue"
      Properties:
        QueueName: ${self:custom.myTopicQueueName}
        VisibilityTimeout: 120
        RedrivePolicy: 
          maxReceiveCount: 3
          deadLetterTargetArn:
            Fn::GetAtt: 
              - MyTopicQueueDeadLetter
              - Arn
    MyTopicQueueDeadLetter:
      Type: "AWS::SQS::Queue"
      Properties:
        QueueName: ${self:custom.myTopicDeadQueueName}

    # Policy to allow SNS to post to SQS
    MyTopicQueuePolicy:
      Type: AWS::SQS::QueuePolicy
      Properties:
        PolicyDocument:
          Version: "2012-10-17"
          Statement:
            Effect: "Allow"
            Principal:
              Service: sns.amazonaws.com
            Resource: 
              - !GetAtt
                - MyTopicQueue
                - Arn
              - !GetAtt
                - MyTopicQueueDeadLetter
                - Arn
            Action: 
              - sqs:*
            Condition:
              ArnEquals:
                aws:SourceArn: !Ref MyTopic
        Queues:
          - Ref: MyTopicQueue
          - Ref: MyTopicQueueDeadLetter

    # Create the subscription for the SNS to SQS queue
    MyTopicSnsToSqsSubscription:
      Type: "AWS::SNS::Subscription"
      Properties:
        TopicArn: !Ref MyTopic
        Endpoint: !GetAtt
          - MyTopicQueue
          - Arn
        Protocol: sqs
        RawMessageDelivery: 'true'
        FilterPolicy:
          type:
            - 'playerLost'
        RedrivePolicy:
          deadLetterTargetArn: !GetAtt
            - MyTopicQueueDeadLetter
            - Arn

不过,我仍然不能 100% 确定该政策,就像在 AWS 控制台中一样,当我查看订阅时,它仍然说它没有权限发布到死信队列(这里我使用的是订阅和 SQS 主队列的相同死信队列),所以我显然遗漏了一些东西。

和CloudFormation类似,在声明主题的时候大概可以直接声明订阅,不过我没试过。

应该足以让你开始


推荐阅读