diff --git a/packages/@aws-cdk/aws-events-targets/README.md b/packages/@aws-cdk/aws-events-targets/README.md index 994c24ab8a0a5..a5c8fde1d9d98 100644 --- a/packages/@aws-cdk/aws-events-targets/README.md +++ b/packages/@aws-cdk/aws-events-targets/README.md @@ -35,7 +35,7 @@ EventBridge. ## Event retry policy and using dead-letter queues -The Codebuild, CodePipeline, Lambda, StepFunctions and LogGroup 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 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). Use [escape hatches](https://docs.aws.amazon.com/cdk/latest/guide/cfn_layer.html) for the other target types. ## Invoke a Lambda function diff --git a/packages/@aws-cdk/aws-events-targets/lib/sqs.ts b/packages/@aws-cdk/aws-events-targets/lib/sqs.ts index 43fb9b8ed15d0..465f0355516cf 100644 --- a/packages/@aws-cdk/aws-events-targets/lib/sqs.ts +++ b/packages/@aws-cdk/aws-events-targets/lib/sqs.ts @@ -1,11 +1,12 @@ import * as events from '@aws-cdk/aws-events'; import * as iam from '@aws-cdk/aws-iam'; import * as sqs from '@aws-cdk/aws-sqs'; +import { addToDeadLetterQueueResourcePolicy, TargetBaseProps, bindBaseTargetConfig } from './util'; /** * Customize the SQS Queue Event Target */ -export interface SqsQueueProps { +export interface SqsQueueProps extends TargetBaseProps { /** * Message Group ID for messages sent to this queue @@ -24,7 +25,6 @@ export interface SqsQueueProps { * @default the entire EventBridge event */ readonly message?: events.RuleTargetInput; - } /** @@ -62,7 +62,12 @@ export class SqsQueue implements events.IRuleTarget { // deduplicated automatically this.queue.grantSendMessages(new iam.ServicePrincipal('events.amazonaws.com', principalOpts)); + if (this.props.deadLetterQueue) { + addToDeadLetterQueueResourcePolicy(rule, this.props.deadLetterQueue); + } + return { + ...bindBaseTargetConfig(this.props), arn: this.queue.queueArn, input: this.props.message, targetResource: this.queue, diff --git a/packages/@aws-cdk/aws-events-targets/test/sqs/integ.sqs-event-rule-target.expected.json b/packages/@aws-cdk/aws-events-targets/test/sqs/integ.sqs-event-rule-target.expected.json index eb2a7dd26ef5f..f35a7a93b9e42 100644 --- a/packages/@aws-cdk/aws-events-targets/test/sqs/integ.sqs-event-rule-target.expected.json +++ b/packages/@aws-cdk/aws-events-targets/test/sqs/integ.sqs-event-rule-target.expected.json @@ -61,6 +61,14 @@ "Arn" ] }, + "DeadLetterConfig": { + "Arn": { + "Fn::GetAtt": [ + "MyDeadLetterQueueD997968A", + "Arn" + ] + } + }, "Id": "Target0" } ] @@ -110,6 +118,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": [ + "MyRuleA44AB831", + "Arn" + ] + } + } + }, + "Effect": "Allow", + "Principal": { + "Service": "events.amazonaws.com" + }, + "Resource": { + "Fn::GetAtt": [ + "MyDeadLetterQueueD997968A", + "Arn" + ] + }, + "Sid": "AllowEventRuleawscdksqseventtargetMyRule0027A8F4" + } + ], + "Version": "2012-10-17" + }, + "Queues": [ + { + "Ref": "MyDeadLetterQueueD997968A" + } + ] + } } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-events-targets/test/sqs/integ.sqs-event-rule-target.ts b/packages/@aws-cdk/aws-events-targets/test/sqs/integ.sqs-event-rule-target.ts index b2b8fb334bff6..f2375dd7c2a37 100644 --- a/packages/@aws-cdk/aws-events-targets/test/sqs/integ.sqs-event-rule-target.ts +++ b/packages/@aws-cdk/aws-events-targets/test/sqs/integ.sqs-event-rule-target.ts @@ -24,6 +24,10 @@ const queue = new sqs.Queue(stack, 'MyQueue', { encryptionMasterKey: key, }); -event.addTarget(new targets.SqsQueue(queue)); +const deadLetterQueue = new sqs.Queue(stack, 'MyDeadLetterQueue'); + +event.addTarget(new targets.SqsQueue(queue, { + deadLetterQueue, +})); app.synth(); diff --git a/packages/@aws-cdk/aws-events-targets/test/sqs/sqs.test.ts b/packages/@aws-cdk/aws-events-targets/test/sqs/sqs.test.ts index 8893a8820f37e..ad2a5296714e6 100644 --- a/packages/@aws-cdk/aws-events-targets/test/sqs/sqs.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/sqs/sqs.test.ts @@ -180,3 +180,75 @@ test('fifo queues are synthesized correctly', () => { ], })); }); + +test('dead letter queue is configured correctly', () => { + const stack = new Stack(); + const queue = new sqs.Queue(stack, 'MyQueue', { fifo: true }); + 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.SqsQueue(queue, { + deadLetterQueue, + })); + + cdkExpect(stack).to(haveResource('AWS::Events::Rule', { + ScheduleExpression: 'rate(1 hour)', + State: 'ENABLED', + Targets: [ + { + Arn: { + 'Fn::GetAtt': [ + 'MyQueueE6CA6235', + 'Arn', + ], + }, + Id: 'Target0', + DeadLetterConfig: { + Arn: { + 'Fn::GetAtt': [ + 'MyDeadLetterQueueD997968A', + 'Arn', + ], + }, + }, + }, + ], + })); +}); + +test('specifying retry policy', () => { + const stack = new Stack(); + const queue = new sqs.Queue(stack, 'MyQueue', { fifo: true }); + const rule = new events.Rule(stack, 'MyRule', { + schedule: events.Schedule.rate(Duration.hours(1)), + }); + + // WHEN + rule.addTarget(new targets.SqsQueue(queue, { + retryAttempts: 2, + maxEventAge: Duration.hours(2), + })); + + cdkExpect(stack).to(haveResource('AWS::Events::Rule', { + ScheduleExpression: 'rate(1 hour)', + State: 'ENABLED', + Targets: [ + { + Arn: { + 'Fn::GetAtt': [ + 'MyQueueE6CA6235', + 'Arn', + ], + }, + Id: 'Target0', + RetryPolicy: { + MaximumEventAgeInSeconds: 7200, + MaximumRetryAttempts: 2, + }, + }, + ], + })); +});