Skip to content

Commit f048d16

Browse files
authored
Merge pull request #466 from bayoudhi/eb_dlq_and_retry_policy
Support configure DLQ on EventBridge Targets
2 parents eda31fb + 58939ad commit f048d16

File tree

3 files changed

+133
-0
lines changed

3 files changed

+133
-0
lines changed

README.md

+68
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ Serverless Framework v2.32.0 or later is required.
5151
- [Specifying a RoleArn](#specifying-a-rolearn)
5252
- [Specifying a custom CloudWatch EventBus](#specifying-a-custom-cloudwatch-eventbus)
5353
- [Specifying a custom EventBridge EventBus](#specifying-a-custom-eventbridge-eventbus)
54+
- [Specifying a DeadLetterQueue](#specifying-a-deadletterqueue)
5455
- [Tags](#tags)
5556
- [Commands](#commands)
5657
- [deploy](#deploy)
@@ -1156,6 +1157,73 @@ stepFunctions:
11561157
...
11571158
```
11581159

1160+
#### Specifying a DeadLetterQueue
1161+
1162+
You can configure a target queue to send dead-letter queue events to:
1163+
1164+
```yml
1165+
stepFunctions:
1166+
stateMachines:
1167+
exampleEventBridgeEventStartsMachine:
1168+
events:
1169+
- eventBridge:
1170+
eventBusName: 'my-custom-event-bus'
1171+
event:
1172+
source:
1173+
- "my.custom.source"
1174+
detail-type:
1175+
- "My Event Type"
1176+
detail:
1177+
state:
1178+
- pending
1179+
deadLetterConfig: 'arn:aws:sqs:us-east-1:012345678910:my-dlq' # SQS Arn
1180+
definition:
1181+
...
1182+
```
1183+
##### Important point
1184+
Don't forget to [Grant permissions to the dead-letter queue](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-rule-dlq.html#eb-dlq-perms), to do that you may need to have the `ARN` of the generated `EventBridge Rule`.
1185+
1186+
In order to get the `ARN` you can use [intrinsic functions](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html) against the `logicalId`, this plugin generates `logicalIds` following this format:
1187+
```ts
1188+
`${StateMachineName}EventsRuleCloudWatchEvent${index}`
1189+
```
1190+
Given this example 👇
1191+
```yml
1192+
stepFunctions:
1193+
stateMachines:
1194+
hellostepfunc1: # <---- StateMachineName
1195+
events:
1196+
- eventBridge:
1197+
eventBusName: 'my-custom-event-bus'
1198+
event:
1199+
source:
1200+
- "my.custom.source"
1201+
- eventBridge:
1202+
eventBusName: 'my-custom-event-bus'
1203+
event:
1204+
source:
1205+
- "my.custom.source"
1206+
deadLetterConfig: 'arn:aws:sqs:us-east-1:012345678910:my-dlq'
1207+
name: myStateMachine
1208+
definition:
1209+
Comment: "A Hello World example of the Amazon States Language using an AWS Lambda Function"
1210+
StartAt: HelloWorld1
1211+
States:
1212+
HelloWorld1:
1213+
Type: Task
1214+
Resource:
1215+
Fn::GetAtt: [hello, Arn]
1216+
End: true
1217+
```
1218+
Then
1219+
```yaml
1220+
# to get the Arn of the 1st EventBridge rule
1221+
!GetAtt Hellostepfunc1EventsRuleCloudWatchEvent1.Arn
1222+
1223+
# to get the Arn of the 2nd EventBridge rule
1224+
!GetAtt Hellostepfunc1EventsRuleCloudWatchEvent2.Arn
1225+
```
1226+
11591227
## Tags
11601228

11611229
You can specify tags on each state machine. Additionally any global tags (specified under `provider` section in your `serverless.yml`) would be merged in as well.

lib/deploy/events/cloudWatchEvent/compileCloudWatchEventEvents.js

+3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ module.exports = {
2323
let Name;
2424
let EventBusName;
2525
let IamRole;
26+
let DeadLetterConfig;
2627

2728
if (typeof eventRule === 'object') {
2829
if (!eventRule.event) {
@@ -45,6 +46,7 @@ module.exports = {
4546
Name = eventRule.name;
4647
EventBusName = JSON.stringify(eventRule.eventBusName);
4748
IamRole = eventRule.iamRole;
49+
DeadLetterConfig = JSON.stringify(eventRule.deadLetterConfig);
4850

4951
if (Input && InputPath) {
5052
const errorMessage = [
@@ -94,6 +96,7 @@ module.exports = {
9496
${InputPath ? `"InputPath": "${InputPath.replace(/\r?\n/g, '')}",` : ''}
9597
"Arn": { "Ref": "${stateMachineLogicalId}" },
9698
"Id": "${cloudWatchId}",
99+
${DeadLetterConfig ? `"DeadLetterConfig":{ "Arn" : ${DeadLetterConfig} },` : ''}
97100
${IamRole ? `"RoleArn":"${IamRole}"` : `"RoleArn": {
98101
"Fn::GetAtt": [
99102
"${cloudWatchIamRoleLogicalId}",

lib/deploy/events/cloudWatchEvent/compileCloudWatchEventEvents.test.js

+62
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,68 @@ describe('awsCompileCloudWatchEventEvents', () => {
327327
.Properties.EventBusName).to.equal('{"Fn::If": [isLocal, "develop", "production"}');
328328
});
329329

330+
itParam('should respect deadLetterConfig variable', ['cloudwatchEvent', 'eventBridge'], (source) => {
331+
serverlessStepFunctions.serverless.service.stepFunctions = {
332+
stateMachines: {
333+
first: {
334+
events: [
335+
{
336+
[source]: {
337+
event: {
338+
source: ['aws.ec2'],
339+
'detail-type': ['EC2 Instance State-change Notification'],
340+
detail: { state: ['pending'] },
341+
},
342+
enabled: false,
343+
input: '{"key":"value"}',
344+
name: 'test-event-name',
345+
eventBusName: 'custom-event-bus',
346+
deadLetterConfig: 'arn:aws:sqs:us-east-1:012345678910:my-dlq',
347+
},
348+
},
349+
],
350+
},
351+
},
352+
};
353+
354+
serverlessStepFunctions.compileCloudWatchEventEvents();
355+
356+
expect(serverlessStepFunctions.serverless.service
357+
.provider.compiledCloudFormationTemplate.Resources.FirstEventsRuleCloudWatchEvent1
358+
.Properties.Targets[0].DeadLetterConfig.Arn).to.equal('arn:aws:sqs:us-east-1:012345678910:my-dlq');
359+
});
360+
361+
itParam('should respect deadLetterConfig intrinsic function', ['cloudwatchEvent', 'eventBridge'], (source) => {
362+
serverlessStepFunctions.serverless.service.stepFunctions = {
363+
stateMachines: {
364+
first: {
365+
events: [
366+
{
367+
[source]: {
368+
event: {
369+
source: ['aws.ec2'],
370+
'detail-type': ['EC2 Instance State-change Notification'],
371+
detail: { state: ['pending'] },
372+
},
373+
enabled: false,
374+
input: '{"key":"value"}',
375+
name: 'test-event-name',
376+
eventBusName: 'custom-event-bus',
377+
deadLetterConfig: '{"Fn::GetAtt":["DLQ","Arn"]}',
378+
},
379+
},
380+
],
381+
},
382+
},
383+
};
384+
385+
serverlessStepFunctions.compileCloudWatchEventEvents();
386+
387+
expect(serverlessStepFunctions.serverless.service
388+
.provider.compiledCloudFormationTemplate.Resources.FirstEventsRuleCloudWatchEvent1
389+
.Properties.Targets[0].DeadLetterConfig.Arn).to.equal('{"Fn::GetAtt":["DLQ","Arn"]}');
390+
});
391+
330392
itParam('should respect input variable as an object', ['cloudwatchEvent', 'eventBridge'], (source) => {
331393
serverlessStepFunctions.serverless.service.stepFunctions = {
332394
stateMachines: {

0 commit comments

Comments
 (0)