Skip to content

Commit abfc0ea

Browse files
authored
feat(events): dead-letter queue support for CodeBuild (#13448)
Resolves #13447 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent e08213f commit abfc0ea

File tree

5 files changed

+190
-2
lines changed

5 files changed

+190
-2
lines changed

packages/@aws-cdk/aws-events-targets/README.md

+33
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,39 @@ const rule = new events.Rule(this, 'rule', {
9090
rule.addTarget(new targets.CloudWatchLogGroup(logGroup));
9191
```
9292

93+
## Trigger a CodeBuild project
94+
95+
Use the `CodeBuildProject` target to trigger a CodeBuild project.
96+
97+
The code snippet below creates a CodeCommit repository that triggers a CodeBuild project
98+
on commit to the master branch. You can optionally attach a
99+
[dead letter queue](https://docs.aws.amazon.com/eventbridge/latest/userguide/rule-dlq.html).
100+
101+
```ts
102+
import * as codebuild from '@aws-sdk/aws-codebuild';
103+
import * as codecommit from '@aws-sdk/aws-codecommit';
104+
import * as sqs from '@aws-sdk/aws-sqs';
105+
import * as targets from "@aws-cdk/aws-events-targets";
106+
107+
const repo = new codecommit.Repository(this, 'MyRepo', {
108+
repositoryName: 'aws-cdk-codebuild-events',
109+
});
110+
111+
const project = new codebuild.Project(this, 'MyProject', {
112+
source: codebuild.Source.codeCommit({ repository: repo }),
113+
});
114+
115+
const deadLetterQueue = new sqs.Queue(this, 'DeadLetterQueue');
116+
117+
// trigger a build when a commit is pushed to the repo
118+
const onCommitRule = repo.onCommit('OnCommit', {
119+
target: new targets.CodeBuildProject(project, {
120+
deadLetterQueue: deadLetterQueue,
121+
}),
122+
branches: ['master'],
123+
});
124+
```
125+
93126
## Trigger a State Machine
94127

95128
Use the `SfnStateMachine` target to trigger a State Machine.

packages/@aws-cdk/aws-events-targets/lib/codebuild.ts

+20-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import * as codebuild from '@aws-cdk/aws-codebuild';
22
import * as events from '@aws-cdk/aws-events';
33
import * as iam from '@aws-cdk/aws-iam';
4-
import { singletonEventRole } from './util';
4+
import * as sqs from '@aws-cdk/aws-sqs';
5+
import { addToDeadLetterQueueResourcePolicy, singletonEventRole } from './util';
56

67
/**
78
* Customize the CodeBuild Event Target
@@ -24,6 +25,18 @@ export interface CodeBuildProjectProps {
2425
* @default - the entire EventBridge event
2526
*/
2627
readonly event?: events.RuleTargetInput;
28+
29+
/**
30+
* The SQS queue to be used as deadLetterQueue.
31+
* Check out the [considerations for using a dead-letter queue](https://docs.aws.amazon.com/eventbridge/latest/userguide/rule-dlq.html#dlq-considerations).
32+
*
33+
* The events not successfully delivered are automatically retried for a specified period of time,
34+
* depending on the retry policy of the target.
35+
* If an event is not delivered before all retry attempts are exhausted, it will be sent to the dead letter queue.
36+
*
37+
* @default - no dead-letter queue
38+
*/
39+
readonly deadLetterQueue?: sqs.IQueue;
2740
}
2841

2942
/**
@@ -39,9 +52,15 @@ export class CodeBuildProject implements events.IRuleTarget {
3952
* Allows using build projects as event rule targets.
4053
*/
4154
public bind(_rule: events.IRule, _id?: string): events.RuleTargetConfig {
55+
56+
if (this.props.deadLetterQueue) {
57+
addToDeadLetterQueueResourcePolicy(_rule, this.props.deadLetterQueue);
58+
}
59+
4260
return {
4361
id: '',
4462
arn: this.project.projectArn,
63+
deadLetterConfig: this.props.deadLetterQueue ? { arn: this.props.deadLetterQueue?.queueArn } : undefined,
4564
role: this.props.eventRole || singletonEventRole(this.project, [
4665
new iam.PolicyStatement({
4766
actions: ['codebuild:StartBuild'],

packages/@aws-cdk/aws-events-targets/test/codebuild/codebuild.test.ts

+81
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { expect, haveResource } from '@aws-cdk/assert';
22
import * as codebuild from '@aws-cdk/aws-codebuild';
33
import * as events from '@aws-cdk/aws-events';
44
import * as iam from '@aws-cdk/aws-iam';
5+
import * as sqs from '@aws-cdk/aws-sqs';
56
import { CfnElement, Stack } from '@aws-cdk/core';
67
import * as targets from '../../lib';
78

@@ -120,4 +121,84 @@ describe('CodeBuild event target', () => {
120121
],
121122
}));
122123
});
124+
125+
test('use a Dead Letter Queue for the rule target', () => {
126+
// GIVEN
127+
const rule = new events.Rule(stack, 'Rule', {
128+
schedule: events.Schedule.expression('rate(1 hour)'),
129+
});
130+
131+
const queue = new sqs.Queue(stack, 'Queue');
132+
133+
// WHEN
134+
const eventInput = {
135+
buildspecOverride: 'buildspecs/hourly.yml',
136+
};
137+
138+
rule.addTarget(
139+
new targets.CodeBuildProject(project, {
140+
event: events.RuleTargetInput.fromObject(eventInput),
141+
deadLetterQueue: queue,
142+
}),
143+
);
144+
145+
// THEN
146+
expect(stack).to(haveResource('AWS::Events::Rule', {
147+
Targets: [
148+
{
149+
Arn: projectArn,
150+
Id: 'Target0',
151+
DeadLetterConfig: {
152+
Arn: {
153+
'Fn::GetAtt': [
154+
'Queue4A7E3555',
155+
'Arn',
156+
],
157+
},
158+
},
159+
Input: JSON.stringify(eventInput),
160+
RoleArn: {
161+
'Fn::GetAtt': ['MyProjectEventsRole5B7D93F5', 'Arn'],
162+
},
163+
},
164+
],
165+
}));
166+
167+
expect(stack).to(haveResource('AWS::SQS::QueuePolicy', {
168+
PolicyDocument: {
169+
Statement: [
170+
{
171+
Action: 'sqs:SendMessage',
172+
Condition: {
173+
ArnEquals: {
174+
'aws:SourceArn': {
175+
'Fn::GetAtt': [
176+
'Rule4C995B7F',
177+
'Arn',
178+
],
179+
},
180+
},
181+
},
182+
Effect: 'Allow',
183+
Principal: {
184+
Service: 'events.amazonaws.com',
185+
},
186+
Resource: {
187+
'Fn::GetAtt': [
188+
'Queue4A7E3555',
189+
'Arn',
190+
],
191+
},
192+
Sid: 'AllowEventRuleRule',
193+
},
194+
],
195+
Version: '2012-10-17',
196+
},
197+
Queues: [
198+
{
199+
Ref: 'Queue4A7E3555',
200+
},
201+
],
202+
}));
203+
});
123204
});

packages/@aws-cdk/aws-events-targets/test/codebuild/integ.project-events.expected.json

+52
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@
4343
"Arn"
4444
]
4545
},
46+
"DeadLetterConfig": {
47+
"Arn": {
48+
"Fn::GetAtt": [
49+
"DeadLetterQueue9F481546",
50+
"Arn"
51+
]
52+
}
53+
},
4654
"Id": "Target0",
4755
"RoleArn": {
4856
"Fn::GetAtt": [
@@ -394,6 +402,50 @@
394402
}
395403
}
396404
},
405+
"DeadLetterQueue9F481546": {
406+
"Type": "AWS::SQS::Queue",
407+
"UpdateReplacePolicy": "Delete",
408+
"DeletionPolicy": "Delete"
409+
},
410+
"DeadLetterQueuePolicyB1FB890C": {
411+
"Type": "AWS::SQS::QueuePolicy",
412+
"Properties": {
413+
"PolicyDocument": {
414+
"Statement": [
415+
{
416+
"Action": "sqs:SendMessage",
417+
"Condition": {
418+
"ArnEquals": {
419+
"aws:SourceArn": {
420+
"Fn::GetAtt": [
421+
"MyRepoOnCommit0E80B304",
422+
"Arn"
423+
]
424+
}
425+
}
426+
},
427+
"Effect": "Allow",
428+
"Principal": {
429+
"Service": "events.amazonaws.com"
430+
},
431+
"Resource": {
432+
"Fn::GetAtt": [
433+
"DeadLetterQueue9F481546",
434+
"Arn"
435+
]
436+
},
437+
"Sid": "AllowEventRuleawscdkcodebuildeventsMyRepoOnCommit0ED1137A"
438+
}
439+
],
440+
"Version": "2012-10-17"
441+
},
442+
"Queues": [
443+
{
444+
"Ref": "DeadLetterQueue9F481546"
445+
}
446+
]
447+
}
448+
},
397449
"MyTopic86869434": {
398450
"Type": "AWS::SNS::Topic"
399451
},

packages/@aws-cdk/aws-events-targets/test/codebuild/integ.project-events.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const project = new codebuild.Project(stack, 'MyProject', {
2020
});
2121

2222
const queue = new sqs.Queue(stack, 'MyQueue');
23+
const deadLetterQueue = new sqs.Queue(stack, 'DeadLetterQueue');
2324

2425
const topic = new sns.Topic(stack, 'MyTopic');
2526
topic.addSubscription(new subs.SqsSubscription(queue));
@@ -39,7 +40,9 @@ project.onPhaseChange('PhaseChange', {
3940

4041
// trigger a build when a commit is pushed to the repo
4142
const onCommitRule = repo.onCommit('OnCommit', {
42-
target: new targets.CodeBuildProject(project),
43+
target: new targets.CodeBuildProject(project, {
44+
deadLetterQueue: deadLetterQueue,
45+
}),
4346
branches: ['master'],
4447
});
4548

0 commit comments

Comments
 (0)