Skip to content

Commit 3f5f32c

Browse files
authored
Merge pull request aws-samples#1660 from bashatah/bashatah-feature-sfn-sns-cdk
2 parents a365c96 + 3acae81 commit 3f5f32c

11 files changed

Lines changed: 363 additions & 0 deletions

File tree

sfn-sns-cdk/.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
*.js
2+
!jest.config.js
3+
*.d.ts
4+
node_modules
5+
6+
# CDK asset staging directory
7+
.cdk.staging
8+
cdk.out

sfn-sns-cdk/README.md

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# AWS Step Functions to Amazon SNS
2+
3+
The Step Functions state machine can be started using the AWS CLI or from another service (e.g. API Gateway) to run the workflow and return the result.
4+
5+
This CDK code deploys a Step Functions workflow that converts milliseconds to second, wait for the time passed to it and then finally sends a message to Amazon SNS.
6+
7+
Learn more about this pattern at Serverless Land Patterns: https://serverlessland.com/patterns/sfn-sns-cdk
8+
9+
Important: this application uses various AWS services and there are costs associated with these services after the Free Tier usage - please see the [AWS Pricing page](https://aws.amazon.com/pricing/) for details. You are responsible for any AWS costs incurred. No warranty is implied in this example.
10+
11+
## Requirements
12+
13+
- [Create an AWS account](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html) if you do not already have one and log in. The IAM user that you use must have sufficient permissions to make necessary AWS service calls and manage AWS resources.
14+
- [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed and configured
15+
- [Git Installed](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
16+
- [AWS CDK](https://docs.aws.amazon.com/cdk/latest/guide/cli.html) installed and configured
17+
18+
## Deployment Instructions
19+
20+
1. Create a new directory, navigate to that directory in a terminal and clone the GitHub repository:
21+
```
22+
git clone https://github.com/aws-samples/serverless-patterns && cd serverless-patterns
23+
```
24+
2. Change directory to the pattern directory:
25+
```
26+
cd sfn-sns-cdk/src
27+
```
28+
3. Install dependencies:
29+
```
30+
npm install
31+
```
32+
4. This project uses typescript as client language for AWS CDK. Run the given command to compile typescript to javascript
33+
```
34+
npm run build
35+
```
36+
5. From the command line, configure AWS CDK (if you had not done it):
37+
```
38+
cdk bootstrap ACCOUNT-NUMBER/REGION # e.g.
39+
cdk bootstrap 1111111111/us-east-1
40+
cdk bootstrap --profile test 1111111111/us-east-1
41+
```
42+
6. Synthesize CloudFormation template from the AWS CDK app
43+
```
44+
cdk synth
45+
```
46+
7. From the command line, use AWS CDK to deploy the AWS resources for the pattern as specified in the `lib/sfn-sns-cdk-stack`
47+
```
48+
cdk deploy
49+
```
50+
8. The CDK template successfully creates a lambda function (to convert from millisecond to second) a SNS Topic and a Step Functions state machine .
51+
52+
9. Note the outputs from the CDK deployment process. It contains the ARN of Step Functions state machine ARN and SNS Topic ARN.
53+
54+
## How it works
55+
56+
* Step Functions receive an execution using the `start-execution` api command with the the message {"waitMilliseconds" : <time-in-milliseconds>} in the input payload.
57+
* The state machine will first call Lambda function to convert milliseconds to seconds.
58+
* The state machine will enter "Wait" state and wait for the time passed to it during execution
59+
* After waiting, Step Functions will send a message by the time it waited to the SNS topic.
60+
61+
## Testing
62+
63+
1. Subscribe your email address to the SNS topic:
64+
```bash
65+
aws sns subscribe --topic-arn ENTER_YOUR_TOPIC_ARN --protocol email --notification-endpoint ENTER_YOUR_EMAIL_ADDRESS
66+
```
67+
1. Click the confirmation link delivered to your email to verify the endpoint.
68+
69+
1. Start Step Functions execution with the command:
70+
```bash
71+
aws stepfunctions start-execution --name "test" --state-machine-arn ENTER_YOUR_STATE_MACHINE_ARN --input {\"waitMilliseconds\":5000}
72+
```
73+
1. The notification message is delivered to your email address.
74+
75+
## Cleanup
76+
77+
78+
1. Delete the stack
79+
```bash
80+
cdk destroy
81+
```
82+
---
83+
84+
Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
85+
86+
SPDX-License-Identifier: MIT-0

sfn-sns-cdk/example-pattern.json

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
{
2+
"title": "AWS Step Functions to SNS",
3+
"description": "Creates a Step Functions workflow to convert milliseconds to seconds and waits a period of time before sending an SNS message.",
4+
"language": "TypeScript",
5+
"level": "200",
6+
"framework": "CDK",
7+
"introBox": {
8+
"headline": "How it works",
9+
"text": [
10+
"Step Functions receive an execution using the `start-execution` api command with the the message {\"waitMilliseconds\" : <time-in-milliseconds>} in the input payload.",
11+
"The state machine will first call Lambda function to convert milliseconds to seconds.",
12+
"The state machine will enter \"Wait\" state and wait for the time passed to it during execution",
13+
"After waiting, Step Functions will send a message to SNS." ]
14+
},
15+
"gitHub": {
16+
"template": {
17+
"repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/sfn-sns-cdk",
18+
"templateURL": "serverless-patterns/sfn-sns-cdk",
19+
"projectFolder": "sfn-sns-cdk",
20+
"templateFile": "src/lib/sfn-sns-cdk-stack.ts"
21+
}
22+
},
23+
"resources": {
24+
"bullets": [
25+
{
26+
"text": "Getting started with the AWS CDK",
27+
"link": "https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html"
28+
},
29+
{
30+
"text": "Setup SNS topic",
31+
"link": "https://docs.aws.amazon.com/sns/latest/dg/sns-create-topic.html"
32+
},
33+
{
34+
"text": "Call Amazon SNS with AWS Step Functions",
35+
"link": "https://docs.aws.amazon.com/step-functions/latest/dg/connect-sns.html"
36+
}
37+
]
38+
},
39+
"deploy": {
40+
"text": [
41+
"cdk deploy"
42+
]
43+
},
44+
"testing": {
45+
"text": [
46+
"See the GitHub repo for detailed testing instructions."
47+
]
48+
},
49+
"cleanup": {
50+
"text": [
51+
"Delete the stack: <code>cdk destroy</code>."
52+
]
53+
},
54+
"authors": [
55+
{
56+
"name": "Abdullah Bashatah",
57+
"bio": "Cloud Support Engineer @ AWS.",
58+
"linkedin": "abdullah-bashatah-92429aba"
59+
}
60+
]
61+
}

sfn-sns-cdk/src/.npmignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
*.ts
2+
!*.d.ts
3+
4+
# CDK asset staging directory
5+
.cdk.staging
6+
cdk.out

sfn-sns-cdk/src/bin/sfn-sns-cdk.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#!/usr/bin/env node
2+
import 'source-map-support/register';
3+
import * as cdk from 'aws-cdk-lib';
4+
import { SfnSnsCdkStack } from '../lib/sfn-sns-cdk-stack';
5+
6+
const app = new cdk.App();
7+
new SfnSnsCdkStack(app, 'SfnSnsCdkStack', {
8+
/* If you don't specify 'env', this stack will be environment-agnostic.
9+
* Account/Region-dependent features and context lookups will not work,
10+
* but a single synthesized template can be deployed anywhere. */
11+
12+
/* Uncomment the next line to specialize this stack for the AWS Account
13+
* and Region that are implied by the current CLI configuration. */
14+
// env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
15+
16+
/* Uncomment the next line if you know exactly what Account and Region you
17+
* want to deploy the stack to. */
18+
// env: { account: '123456789012', region: 'us-east-1' },
19+
20+
/* For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html */
21+
});

sfn-sns-cdk/src/cdk.json

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
{
2+
"app": "npx ts-node --prefer-ts-exts bin/sfn-sns-cdk.ts",
3+
"watch": {
4+
"include": [
5+
"**"
6+
],
7+
"exclude": [
8+
"README.md",
9+
"cdk*.json",
10+
"**/*.d.ts",
11+
"**/*.js",
12+
"tsconfig.json",
13+
"package*.json",
14+
"yarn.lock",
15+
"node_modules",
16+
"test"
17+
]
18+
},
19+
"context": {
20+
"@aws-cdk/aws-lambda:recognizeLayerVersion": true,
21+
"@aws-cdk/core:checkSecretUsage": true,
22+
"@aws-cdk/core:target-partitions": [
23+
"aws",
24+
"aws-cn"
25+
],
26+
"@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
27+
"@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
28+
"@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true,
29+
"@aws-cdk/aws-iam:minimizePolicies": true,
30+
"@aws-cdk/core:validateSnapshotRemovalPolicy": true,
31+
"@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
32+
"@aws-cdk/aws-s3:createDefaultLoggingPolicy": true,
33+
"@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true,
34+
"@aws-cdk/aws-apigateway:disableCloudWatchRole": true,
35+
"@aws-cdk/core:enablePartitionLiterals": true,
36+
"@aws-cdk/aws-events:eventsTargetQueueSameAccount": true,
37+
"@aws-cdk/aws-iam:standardizedServicePrincipals": true,
38+
"@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true,
39+
"@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true,
40+
"@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true,
41+
"@aws-cdk/aws-route53-patters:useCertificate": true,
42+
"@aws-cdk/customresources:installLatestAwsSdkDefault": false,
43+
"@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true,
44+
"@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true,
45+
"@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true,
46+
"@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true,
47+
"@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true,
48+
"@aws-cdk/aws-redshift:columnId": true,
49+
"@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true,
50+
"@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true,
51+
"@aws-cdk/aws-apigateway:requestValidatorUniqueId": true,
52+
"@aws-cdk/aws-kms:aliasNameRef": true,
53+
"@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true,
54+
"@aws-cdk/core:includePrefixInUniqueNameGeneration": true,
55+
"@aws-cdk/aws-efs:denyAnonymousAccess": true,
56+
"@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true,
57+
"@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true,
58+
"@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true
59+
}
60+
}

sfn-sns-cdk/src/jest.config.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module.exports = {
2+
testEnvironment: 'node',
3+
roots: ['<rootDir>/test'],
4+
testMatch: ['**/*.test.ts'],
5+
transform: {
6+
'^.+\\.tsx?$': 'ts-jest'
7+
}
8+
};
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import * as cdk from 'aws-cdk-lib';
2+
import { Construct } from 'constructs';
3+
import { aws_stepfunctions as sfn, aws_stepfunctions_tasks as tasks, aws_sns as sns, aws_lambda as lambda, CfnOutput } from 'aws-cdk-lib';
4+
5+
export class SfnSnsCdkStack extends cdk.Stack {
6+
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
7+
super(scope, id, props);
8+
9+
const convertToSeconds = new tasks.EvaluateExpression(this, 'Convert to seconds', {
10+
expression: '$.waitMilliseconds / 1000',
11+
resultPath: '$.waitSeconds',
12+
});
13+
14+
const wait = new sfn.Wait(this, 'Wait', {
15+
time: sfn.WaitTime.secondsPath('$.waitSeconds'),
16+
});
17+
18+
const snsTopic = new sns.Topic(this, 'state-machine-topic');
19+
20+
const publishMessage = new tasks.SnsPublish(this, 'Publish message', {
21+
topic: snsTopic,
22+
message: sfn.TaskInput.fromJsonPathAt("States.Format('Task waited for {} seconds!', $.waitSeconds)"),
23+
resultPath: '$.sns',
24+
});
25+
26+
27+
28+
const StateMachine = new sfn.StateMachine(this, 'StateMachine', {
29+
definition: convertToSeconds
30+
.next(wait)
31+
.next(publishMessage)
32+
});
33+
34+
new CfnOutput(this, 'StateMachineARN', { value: StateMachine.stateMachineArn });
35+
new CfnOutput(this, 'SnsTopicARN', { value: snsTopic.topicArn });
36+
}
37+
}
38+

sfn-sns-cdk/src/package.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"name": "sfn-sns-cdk",
3+
"version": "0.1.0",
4+
"bin": {
5+
"sfn-sns-cdk": "bin/sfn-sns-cdk.js"
6+
},
7+
"scripts": {
8+
"build": "tsc",
9+
"watch": "tsc -w",
10+
"test": "jest",
11+
"cdk": "cdk"
12+
},
13+
"devDependencies": {
14+
"@types/jest": "^29.5.4",
15+
"@types/node": "20.5.7",
16+
"aws-cdk": "2.94.0",
17+
"jest": "^29.6.4",
18+
"ts-jest": "^29.1.1",
19+
"ts-node": "^10.9.1",
20+
"typescript": "~5.2.2"
21+
},
22+
"dependencies": {
23+
"aws-cdk-lib": "2.94.0",
24+
"constructs": "^10.0.0",
25+
"source-map-support": "^0.5.21"
26+
}
27+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// import * as cdk from 'aws-cdk-lib';
2+
// import { Template } from 'aws-cdk-lib/assertions';
3+
// import * as SfnSnsCdk from '../lib/sfn-sns-cdk-stack';
4+
5+
// example test. To run these tests, uncomment this file along with the
6+
// example resource in lib/sfn-sns-cdk-stack.ts
7+
test('SQS Queue Created', () => {
8+
// const app = new cdk.App();
9+
// // WHEN
10+
// const stack = new SfnSnsCdk.SfnSnsCdkStack(app, 'MyTestStack');
11+
// // THEN
12+
// const template = Template.fromStack(stack);
13+
14+
// template.hasResourceProperties('AWS::SQS::Queue', {
15+
// VisibilityTimeout: 300
16+
// });
17+
});

0 commit comments

Comments
 (0)