├── License.txt ├── README.md ├── final_state_lambda ├── handle.py └── zappa_settings.json ├── greater_than_lambda ├── handle.py └── zappa_settings.json ├── images ├── algorithm.png ├── example.png ├── sms-rec.png └── statemachine.png ├── less_than_lambda ├── handle.py └── zappa_settings.json ├── requirement.txt ├── steps.json └── sub_numbers_lambda ├── handle.py └── zappa_settings.json /License.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Osama 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AWS Step Functions 2 | "AWS Step Functions is a web service that enables you to coordinate the components of distributed applications and microservices using visual workflows. You build applications from individual components that each perform a discrete function, or task, allowing you to scale and change applications quickly." 3 | 4 | I've learned Step Functions by applying the following example and I hope it can help you in 5 | 6 | # Algorithm (Example) 7 | In this example, the algorithm takes two input numbers and subtract them,then : 8 | - If the result is larger than 100 the user should receive a SMS with a random number between 100-1000. 9 | - If it's less, then the random number in the SMS should be from 0-100. 10 | - Else it's failed scenario, with a dead end. 11 | 12 |

13 | 14 |

15 | 16 | In step functions, you can consider that each process block is an AWS Lambda Function, that takes the output of previous state as input for the current state. Therefore we have 4 Lambda functions in this example: 17 | - sub_numbers_lambda | takes { key1 : X, key2 : Y} and returns { number : Z } 18 | - greater_than_lambda | returns { final_number : rand(100,100) } 19 | - less_than_lambda | returns { final_number : rand(0,100) } 20 | - final_state_lambda | takes { final_number : C } 21 | 22 | Step functions are described with json format, where you should define : 23 | - start_state (StartAt) 24 | - final_state (End) 25 | - next_state (Next) 26 | - choise_state ( Type : Choice), which supports many comparison operators. 27 | 28 | # Step Functions Description Example 29 | ``` 30 | "StartAt": "SubNumbers", 31 | "States": { 32 | "SubNumbers": { 33 | "Type": "Task", 34 | "Resource": "ARN:OF:sub-numbers", 35 | "Next": "ChoiceState" 36 | }, 37 | "ChoiceState": { 38 | "Type" : "Choice", 39 | "Choices": [ 40 | { 41 | "Variable": "$.number", 42 | "NumericGreaterThan": 100, 43 | "Next": "GreateThan" 44 | }, 45 | { 46 | "Variable": "$.number", 47 | "NumericEquals": 100, 48 | "Next": "LessThan" 49 | } 50 | ], 51 | "Default": "EqualTo" 52 | }, 53 | 54 | "GreateThan": { 55 | "Type" : "Task", 56 | "Resource": "ARN:OF:greater-than-lambda", 57 | "Next": "FinalState" 58 | }, 59 | 60 | "LessThan": { 61 | "Type" : "Task", 62 | "Resource": "ARN:OF:less-than-lambda", 63 | "Next": "FinalState" 64 | }, 65 | 66 | "EqualTo": { 67 | "Type": "Fail", 68 | "Cause": "No Matches!", 69 | "End": true 70 | }, 71 | 72 | "FinalState": { 73 | "Type": "Task", 74 | "Resource": "ARN:OF:final-state-lambda", 75 | "End": true 76 | } 77 | } 78 | } 79 | ``` 80 | 81 | # Apply it 82 | 1- Clone this repo 83 | 2- Create a python virtualenv inside it, and install pip requirements 84 | ``` 85 | $ git clone git@github.com:OsamaJBR/teach-me-aws-stepfunctions.git 86 | $ cd teach-me-aws-stepfunctions 87 | $ virtualenv env 88 | $ source env/bin/activate 89 | $ pip install -r requirement.txt 90 | ``` 91 | 3- Start deploying functions using [Zappa](https://github.com/Miserlou/Zappa) 92 | ``` 93 | $ cd sub_numbers_lambda; zappa deploy develop 94 | $ cd greater_than_lambda; zappa deploy develop 95 | $ cd less_than_lambda; zappa deploy develop 96 | ``` 97 | 4- Go to Amazon Console (AWS Lambda) page and get all ARN for the above lambda functions 98 | 5- Edit steps.json file and add ARN inside the related state definition 99 | ``` 100 | ... 101 | "SubNumbers": { 102 | "Type": "Task", 103 | "Resource": "XXXXXXXXXXXX", 104 | "Next": "ChoiceState" 105 | }, 106 | ... 107 | ``` 108 | 6- Edit final_state_lambda by adding the SNS Topic ARN in the code, then deploy the function using zappa again 109 | ``` 110 | $ cd final_state_lambda; vim handle.py 111 | ... 112 | response = client.publish( 113 | TargetArn="XXXXXXXXXXXXXXX", 114 | Message=json.dumps({'default': json.dumps(message)}), 115 | MessageStructure='json' 116 | ) 117 | ... 118 | $ zappa deploy develop 119 | ``` 120 | 7- Go to Amazon Step Function page, the Create State Machine. Past the edited steps.json inside the Code panel. Then you should see this in the Preview section. 121 |

122 | 123 |

124 | * If everything is ok, create it. 125 | 126 | # How to test it 127 | 1- Go to the new state machine, and press on new execution. 128 | 2- Insert the following as input, and start the execution. 129 | ``` 130 | { 131 | "key1" : 100, 132 | "key2" : 300 133 | } 134 | ``` 135 |

136 | 137 |

138 | 3- The final state suppose to send an SMS to the phone number subscribed in the SNS Topic. 139 |

140 | 141 |

142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /final_state_lambda/handle.py: -------------------------------------------------------------------------------- 1 | import json 2 | import boto3 3 | import inflect 4 | 5 | def lambda_handler(event,context): 6 | inflect_engine = inflect.engine() 7 | number = inflect_engine.number_to_words(event['final_number']) 8 | message = {"DelMeMessage": "The StepFunctions Result is %r" %number} 9 | client = boto3.client('sns') 10 | response = client.publish( 11 | TargetArn="SNS-TOPIC-ARN", 12 | Message=json.dumps({'default': json.dumps(message)}), 13 | MessageStructure='json' 14 | ) 15 | -------------------------------------------------------------------------------- /final_state_lambda/zappa_settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "develop": { 3 | "keep_warm": false, 4 | "apigateway_enabled" : false, 5 | "memory_size" : 128, 6 | "debug": false, 7 | "lambda_handler" : "handle.lambda_handler" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /greater_than_lambda/handle.py: -------------------------------------------------------------------------------- 1 | import json 2 | import random 3 | 4 | def lambda_handler(event,context): 5 | final_number = random.randint(100,1000) 6 | return {"final_number" : final_number} -------------------------------------------------------------------------------- /greater_than_lambda/zappa_settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "develop": { 3 | "keep_warm": false, 4 | "apigateway_enabled" : false, 5 | "memory_size" : 128, 6 | "debug": false , 7 | "lambda_handler": "handle.lambda_handler" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /images/algorithm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OsamaJBR/teach-me-aws-stepfunctions/1f3e93899d2adadffdc6469ab92d21a545eb22a1/images/algorithm.png -------------------------------------------------------------------------------- /images/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OsamaJBR/teach-me-aws-stepfunctions/1f3e93899d2adadffdc6469ab92d21a545eb22a1/images/example.png -------------------------------------------------------------------------------- /images/sms-rec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OsamaJBR/teach-me-aws-stepfunctions/1f3e93899d2adadffdc6469ab92d21a545eb22a1/images/sms-rec.png -------------------------------------------------------------------------------- /images/statemachine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OsamaJBR/teach-me-aws-stepfunctions/1f3e93899d2adadffdc6469ab92d21a545eb22a1/images/statemachine.png -------------------------------------------------------------------------------- /less_than_lambda/handle.py: -------------------------------------------------------------------------------- 1 | import json 2 | import random 3 | 4 | def lambda_handler(event,context): 5 | final_number = random.randint(0,100) 6 | return {"final_number" : final_number} -------------------------------------------------------------------------------- /less_than_lambda/zappa_settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "develop": { 3 | "keep_warm": false, 4 | "apigateway_enabled" : false, 5 | "memory_size" : 128, 6 | "debug": false, 7 | "lambda_handler": "handle.lambda_handler" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /requirement.txt: -------------------------------------------------------------------------------- 1 | boto3 2 | zappa 3 | inflect 4 | 5 | -------------------------------------------------------------------------------- /steps.json: -------------------------------------------------------------------------------- 1 | { 2 | "Comment": "Example of ChoiceState using AWS StepFunctions", 3 | "StartAt": "SubNumbers", 4 | "States": { 5 | "SubNumbers": { 6 | "Type": "Task", 7 | "Resource": "ARN:OF:sub-numbers", 8 | "Next": "ChoiceState" 9 | }, 10 | "ChoiceState": { 11 | "Type" : "Choice", 12 | "Choices": [ 13 | { 14 | "Variable": "$.number", 15 | "NumericGreaterThan": 100, 16 | "Next": "GreateThan" 17 | }, 18 | { 19 | "Variable": "$.number", 20 | "NumericLessThan": 100, 21 | "Next": "LessThan" 22 | } 23 | ], 24 | "Default": "EqualTo" 25 | }, 26 | 27 | "GreateThan": { 28 | "Type" : "Task", 29 | "Resource": "ARN:OF:greater-than-lambda", 30 | "Next": "FinalState" 31 | }, 32 | 33 | "LessThan": { 34 | "Type" : "Task", 35 | "Resource": "ARN:OF:less-than-lambda", 36 | "Next": "FinalState" 37 | }, 38 | 39 | "EqualTo": { 40 | "Type": "Fail", 41 | "Cause": "No Matches!" 42 | }, 43 | 44 | "FinalState": { 45 | "Type": "Task", 46 | "Resource": "ARN:OF:final-state-lambda", 47 | "End": true 48 | } 49 | } 50 | } 51 | 52 | -------------------------------------------------------------------------------- /sub_numbers_lambda/handle.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | def lambda_handler(event, context): 4 | number_1 = int(event['key1']) 5 | number_2 = int(event['key2']) 6 | return {"number" : abs(number_1 - number_2)} 7 | -------------------------------------------------------------------------------- /sub_numbers_lambda/zappa_settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "develop": { 3 | "keep_warm": false, 4 | "apigateway_enabled" : false, 5 | "memory_size" : 128, 6 | "debug": false, 7 | "lambda_handler": "handle.lambda_handler" 8 | 9 | } 10 | } 11 | --------------------------------------------------------------------------------