Skip to content

Commit

Permalink
feat(events-targets): Add DLQ support for SNS target (#20062)
Browse files Browse the repository at this point in the history
Add DLQ support for SNS target.

Closes #19741.

----

### All Submissions:

* [X] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md)

### Adding new Unconventional Dependencies:

* [ ] This PR adds new unconventional dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md/#adding-new-unconventional-dependencies)

### New Features

* [X] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/master/INTEGRATION_TESTS.md)?
	* [X] Did you use `yarn integ` to deploy the infrastructure and generate the snapshot (i.e. `yarn integ` without `--dry-run`)?

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
jumic committed Jun 14, 2022
1 parent a014c30 commit 1148a47
Show file tree
Hide file tree
Showing 9 changed files with 202 additions and 7 deletions.
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-events-targets/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ EventBridge.

## Event retry policy and using dead-letter queues

The Codebuild, CodePipeline, Lambda, StepFunctions, LogGroup and SQSQueue targets support attaching a [dead letter queue and setting retry policies](https://docs.aws.amazon.com/eventbridge/latest/userguide/rule-dlq.html). See the [lambda example](#invoke-a-lambda-function).
The Codebuild, CodePipeline, Lambda, StepFunctions, LogGroup, SQSQueue and SNSTopic targets support attaching a [dead letter queue and setting retry policies](https://docs.aws.amazon.com/eventbridge/latest/userguide/rule-dlq.html). See the [lambda example](#invoke-a-lambda-function).
Use [escape hatches](https://docs.aws.amazon.com/cdk/latest/guide/cfn_layer.html) for the other target types.

## Invoke a Lambda function
Expand Down
8 changes: 7 additions & 1 deletion packages/@aws-cdk/aws-events-targets/lib/sns.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import * as events from '@aws-cdk/aws-events';
import * as iam from '@aws-cdk/aws-iam';
import * as sns from '@aws-cdk/aws-sns';
import { addToDeadLetterQueueResourcePolicy, TargetBaseProps, bindBaseTargetConfig } from './util';

/**
* Customize the SNS Topic Event Target
*/
export interface SnsTopicProps {
export interface SnsTopicProps extends TargetBaseProps {
/**
* The message to send to the topic
*
Expand Down Expand Up @@ -38,7 +39,12 @@ export class SnsTopic implements events.IRuleTarget {
// deduplicated automatically
this.topic.grantPublish(new iam.ServicePrincipal('events.amazonaws.com'));

if (this.props.deadLetterQueue) {
addToDeadLetterQueueResourcePolicy(_rule, this.props.deadLetterQueue);
}

return {
...bindBaseTargetConfig(this.props),
arn: this.topic.topicArn,
input: this.props.message,
targetResource: this.topic,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ const event = new events.Rule(stack, 'EveryMinute', {
const queue = new sqs.Queue(stack, 'MyQueue');
topic.addSubscription(new subs.SqsSubscription(queue));

event.addTarget(new targets.SnsTopic(topic));
const deadLetterQueue = new sqs.Queue(stack, 'MyDeadLetterQueue');

event.addTarget(new targets.SnsTopic(topic, {
deadLetterQueue,
}));

app.synth();
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@
"Arn": {
"Ref": "MyTopic86869434"
},
"DeadLetterConfig": {
"Arn": {
"Fn::GetAtt": [
"MyDeadLetterQueueD997968A",
"Arn"
]
}
},
"Id": "Target0"
}
]
Expand Down Expand Up @@ -98,6 +106,50 @@
]
}
}
},
"MyDeadLetterQueueD997968A": {
"Type": "AWS::SQS::Queue",
"UpdateReplacePolicy": "Delete",
"DeletionPolicy": "Delete"
},
"MyDeadLetterQueuePolicyCC35D52C": {
"Type": "AWS::SQS::QueuePolicy",
"Properties": {
"PolicyDocument": {
"Statement": [
{
"Action": "sqs:SendMessage",
"Condition": {
"ArnEquals": {
"aws:SourceArn": {
"Fn::GetAtt": [
"EveryMinute2BBCEA8F",
"Arn"
]
}
}
},
"Effect": "Allow",
"Principal": {
"Service": "events.amazonaws.com"
},
"Resource": {
"Fn::GetAtt": [
"MyDeadLetterQueueD997968A",
"Arn"
]
},
"Sid": "AllowEventRuleawscdksnseventtargetEveryMinuteD1FC5963"
}
],
"Version": "2012-10-17"
},
"Queues": [
{
"Ref": "MyDeadLetterQueueD997968A"
}
]
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"version":"17.0.0"}
{"version":"19.0.0"}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"version": "18.0.0",
"version": "19.0.0",
"testCases": {
"aws-events-targets/test/sns/integ.sns-event-rule-target": {
"sns/integ.sns-event-rule-target": {
"stacks": [
"aws-cdk-sns-event-target"
],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "17.0.0",
"version": "19.0.0",
"artifacts": {
"Tree": {
"type": "cdk:tree",
Expand Down Expand Up @@ -50,6 +50,18 @@
"type": "aws:cdk:logicalId",
"data": "MyQueueawscdksnseventtargetMyTopicB7575CD87304D383"
}
],
"/aws-cdk-sns-event-target/MyDeadLetterQueue/Resource": [
{
"type": "aws:cdk:logicalId",
"data": "MyDeadLetterQueueD997968A"
}
],
"/aws-cdk-sns-event-target/MyDeadLetterQueue/Policy/Resource": [
{
"type": "aws:cdk:logicalId",
"data": "MyDeadLetterQueuePolicyCC35D52C"
}
]
},
"displayName": "aws-cdk-sns-event-target"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,14 @@
"id": "Target0",
"arn": {
"Ref": "MyTopic86869434"
},
"deadLetterConfig": {
"arn": {
"Fn::GetAtt": [
"MyDeadLetterQueueD997968A",
"Arn"
]
}
}
}
]
Expand Down Expand Up @@ -222,6 +230,85 @@
"fqn": "@aws-cdk/aws-sqs.Queue",
"version": "0.0.0"
}
},
"MyDeadLetterQueue": {
"id": "MyDeadLetterQueue",
"path": "aws-cdk-sns-event-target/MyDeadLetterQueue",
"children": {
"Resource": {
"id": "Resource",
"path": "aws-cdk-sns-event-target/MyDeadLetterQueue/Resource",
"attributes": {
"aws:cdk:cloudformation:type": "AWS::SQS::Queue",
"aws:cdk:cloudformation:props": {}
},
"constructInfo": {
"fqn": "@aws-cdk/aws-sqs.CfnQueue",
"version": "0.0.0"
}
},
"Policy": {
"id": "Policy",
"path": "aws-cdk-sns-event-target/MyDeadLetterQueue/Policy",
"children": {
"Resource": {
"id": "Resource",
"path": "aws-cdk-sns-event-target/MyDeadLetterQueue/Policy/Resource",
"attributes": {
"aws:cdk:cloudformation:type": "AWS::SQS::QueuePolicy",
"aws:cdk:cloudformation:props": {
"policyDocument": {
"Statement": [
{
"Action": "sqs:SendMessage",
"Condition": {
"ArnEquals": {
"aws:SourceArn": {
"Fn::GetAtt": [
"EveryMinute2BBCEA8F",
"Arn"
]
}
}
},
"Effect": "Allow",
"Principal": {
"Service": "events.amazonaws.com"
},
"Resource": {
"Fn::GetAtt": [
"MyDeadLetterQueueD997968A",
"Arn"
]
},
"Sid": "AllowEventRuleawscdksnseventtargetEveryMinuteD1FC5963"
}
],
"Version": "2012-10-17"
},
"queues": [
{
"Ref": "MyDeadLetterQueueD997968A"
}
]
}
},
"constructInfo": {
"fqn": "@aws-cdk/aws-sqs.CfnQueuePolicy",
"version": "0.0.0"
}
}
},
"constructInfo": {
"fqn": "@aws-cdk/aws-sqs.QueuePolicy",
"version": "0.0.0"
}
}
},
"constructInfo": {
"fqn": "@aws-cdk/aws-sqs.Queue",
"version": "0.0.0"
}
}
},
"constructInfo": {
Expand Down
34 changes: 34 additions & 0 deletions packages/@aws-cdk/aws-events-targets/test/sns/sns.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Template } from '@aws-cdk/assertions';
import * as events from '@aws-cdk/aws-events';
import * as sns from '@aws-cdk/aws-sns';
import * as sqs from '@aws-cdk/aws-sqs';
import { Duration, Stack } from '@aws-cdk/core';
import * as targets from '../../lib';

Expand Down Expand Up @@ -74,3 +75,36 @@ test('multiple uses of a topic as a target results in a single policy statement'
Topics: [{ Ref: 'MyTopic86869434' }],
});
});

test('dead letter queue is configured correctly', () => {
const stack = new Stack();
const topic = new sns.Topic(stack, 'MyTopic');
const deadLetterQueue = new sqs.Queue(stack, 'MyDeadLetterQueue');
const rule = new events.Rule(stack, 'MyRule', {
schedule: events.Schedule.rate(Duration.hours(1)),
});

// WHEN
rule.addTarget(new targets.SnsTopic(topic, {
deadLetterQueue,
}));

Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', {
ScheduleExpression: 'rate(1 hour)',
State: 'ENABLED',
Targets: [
{
Arn: { Ref: 'MyTopic86869434' },
Id: 'Target0',
DeadLetterConfig: {
Arn: {
'Fn::GetAtt': [
'MyDeadLetterQueueD997968A',
'Arn',
],
},
},
},
],
});
});

0 comments on commit 1148a47

Please sign in to comment.