Skip to content

Support configure DLQ on EventBridge Targets #466

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ Serverless Framework v2.32.0 or later is required.
- [Specifying a RoleArn](#specifying-a-rolearn)
- [Specifying a custom CloudWatch EventBus](#specifying-a-custom-cloudwatch-eventbus)
- [Specifying a custom EventBridge EventBus](#specifying-a-custom-eventbridge-eventbus)
- [Specifying a DeadLetterQueue](#specifying-a-deadletterqueue)
- [Tags](#tags)
- [Commands](#commands)
- [deploy](#deploy)
Expand Down Expand Up @@ -1156,6 +1157,73 @@ stepFunctions:
...
```

#### Specifying a DeadLetterQueue

You can configure a target queue to send dead-letter queue events to:

```yml
stepFunctions:
stateMachines:
exampleEventBridgeEventStartsMachine:
events:
- eventBridge:
eventBusName: 'my-custom-event-bus'
event:
source:
- "my.custom.source"
detail-type:
- "My Event Type"
detail:
state:
- pending
deadLetterConfig: 'arn:aws:sqs:us-east-1:012345678910:my-dlq' # SQS Arn
definition:
...
```
##### Important point
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`.

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:
```ts
`${StateMachineName}EventsRuleCloudWatchEvent${index}`
```
Given this example 👇
```yml
stepFunctions:
stateMachines:
hellostepfunc1: # <---- StateMachineName
events:
- eventBridge:
eventBusName: 'my-custom-event-bus'
event:
source:
- "my.custom.source"
- eventBridge:
eventBusName: 'my-custom-event-bus'
event:
source:
- "my.custom.source"
deadLetterConfig: 'arn:aws:sqs:us-east-1:012345678910:my-dlq'
name: myStateMachine
definition:
Comment: "A Hello World example of the Amazon States Language using an AWS Lambda Function"
StartAt: HelloWorld1
States:
HelloWorld1:
Type: Task
Resource:
Fn::GetAtt: [hello, Arn]
End: true
```
Then
```yaml
# to get the Arn of the 1st EventBridge rule
!GetAtt Hellostepfunc1EventsRuleCloudWatchEvent1.Arn

# to get the Arn of the 2nd EventBridge rule
!GetAtt Hellostepfunc1EventsRuleCloudWatchEvent2.Arn
```

## Tags

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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ module.exports = {
let Name;
let EventBusName;
let IamRole;
let DeadLetterConfig;

if (typeof eventRule === 'object') {
if (!eventRule.event) {
Expand All @@ -45,6 +46,7 @@ module.exports = {
Name = eventRule.name;
EventBusName = JSON.stringify(eventRule.eventBusName);
IamRole = eventRule.iamRole;
DeadLetterConfig = JSON.stringify(eventRule.deadLetterConfig);

if (Input && InputPath) {
const errorMessage = [
Expand Down Expand Up @@ -94,6 +96,7 @@ module.exports = {
${InputPath ? `"InputPath": "${InputPath.replace(/\r?\n/g, '')}",` : ''}
"Arn": { "Ref": "${stateMachineLogicalId}" },
"Id": "${cloudWatchId}",
${DeadLetterConfig ? `"DeadLetterConfig":{ "Arn" : ${DeadLetterConfig} },` : ''}
${IamRole ? `"RoleArn":"${IamRole}"` : `"RoleArn": {
"Fn::GetAtt": [
"${cloudWatchIamRoleLogicalId}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,68 @@ describe('awsCompileCloudWatchEventEvents', () => {
.Properties.EventBusName).to.equal('{"Fn::If": [isLocal, "develop", "production"}');
});

itParam('should respect deadLetterConfig variable', ['cloudwatchEvent', 'eventBridge'], (source) => {
serverlessStepFunctions.serverless.service.stepFunctions = {
stateMachines: {
first: {
events: [
{
[source]: {
event: {
source: ['aws.ec2'],
'detail-type': ['EC2 Instance State-change Notification'],
detail: { state: ['pending'] },
},
enabled: false,
input: '{"key":"value"}',
name: 'test-event-name',
eventBusName: 'custom-event-bus',
deadLetterConfig: 'arn:aws:sqs:us-east-1:012345678910:my-dlq',
},
},
],
},
},
};

serverlessStepFunctions.compileCloudWatchEventEvents();

expect(serverlessStepFunctions.serverless.service
.provider.compiledCloudFormationTemplate.Resources.FirstEventsRuleCloudWatchEvent1
.Properties.Targets[0].DeadLetterConfig.Arn).to.equal('arn:aws:sqs:us-east-1:012345678910:my-dlq');
});

itParam('should respect deadLetterConfig intrinsic function', ['cloudwatchEvent', 'eventBridge'], (source) => {
serverlessStepFunctions.serverless.service.stepFunctions = {
stateMachines: {
first: {
events: [
{
[source]: {
event: {
source: ['aws.ec2'],
'detail-type': ['EC2 Instance State-change Notification'],
detail: { state: ['pending'] },
},
enabled: false,
input: '{"key":"value"}',
name: 'test-event-name',
eventBusName: 'custom-event-bus',
deadLetterConfig: '{"Fn::GetAtt":["DLQ","Arn"]}',
},
},
],
},
},
};

serverlessStepFunctions.compileCloudWatchEventEvents();

expect(serverlessStepFunctions.serverless.service
.provider.compiledCloudFormationTemplate.Resources.FirstEventsRuleCloudWatchEvent1
.Properties.Targets[0].DeadLetterConfig.Arn).to.equal('{"Fn::GetAtt":["DLQ","Arn"]}');
});

itParam('should respect input variable as an object', ['cloudwatchEvent', 'eventBridge'], (source) => {
serverlessStepFunctions.serverless.service.stepFunctions = {
stateMachines: {
Expand Down