├── README.md ├── testrequest.py ├── testworker.py ├── LICENSE ├── testcreate.py └── testdecider.py /README.md: -------------------------------------------------------------------------------- 1 | # aws-swf-boto3 2 | Sample implementation of a simple AWS SWF app using boto3. 3 | 4 | Inspired by http://boto.cloudhackers.com/en/latest/swf_tut.html for an earlier version of boto. 5 | -------------------------------------------------------------------------------- /testrequest.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import boto3 4 | 5 | swf = boto3.client('swf') 6 | 7 | DOMAIN = "yourtestdomain" 8 | WORKFLOW = "yourtestworkflow" 9 | TASKNAME = "yourtaskname" 10 | VERSION = "0.1" 11 | TASKLIST = "testlist" 12 | 13 | response = swf.start_workflow_execution( 14 | domain=DOMAIN, 15 | workflowId='test-1001', 16 | workflowType={ 17 | "name": WORKFLOW, 18 | "version": VERSION 19 | }, 20 | taskList={ 21 | 'name': TASKLIST 22 | }, 23 | input='' 24 | ) 25 | 26 | print "Workflow requested: ", response 27 | 28 | 29 | -------------------------------------------------------------------------------- /testworker.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import boto3 4 | from botocore.client import Config 5 | 6 | botoConfig = Config(connect_timeout=50, read_timeout=70) 7 | swf = boto3.client('swf', config=botoConfig) 8 | 9 | DOMAIN = "yourtestdomain" 10 | WORKFLOW = "yourtestworkflow" 11 | TASKNAME = "yourtaskname" 12 | VERSION = "0.1" 13 | TASKLIST = "testlist" 14 | 15 | print "Listening for Worker Tasks" 16 | 17 | while True: 18 | 19 | task = swf.poll_for_activity_task( 20 | domain=DOMAIN, 21 | taskList={'name': TASKLIST}, 22 | identity='worker-1') 23 | 24 | if 'taskToken' not in task: 25 | print "Poll timed out, no new task. Repoll" 26 | 27 | else: 28 | print "New task arrived" 29 | 30 | swf.respond_activity_task_completed( 31 | taskToken=task['taskToken'], 32 | result='success' 33 | ) 34 | 35 | print "Task Done" 36 | 37 | 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 John Ludwig 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 | -------------------------------------------------------------------------------- /testcreate.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import boto3 4 | from botocore.exceptions import ClientError 5 | 6 | DOMAIN = "yourtestdomain" 7 | WORKFLOW = "yourtestworkflow" 8 | TASKNAME = "yourtaskname" 9 | VERSION = "0.1" 10 | TASKLIST = "testlist" 11 | 12 | swf = boto3.client('swf') 13 | 14 | try: 15 | swf.register_domain( 16 | name=DOMAIN, 17 | description="Test SWF domain", 18 | workflowExecutionRetentionPeriodInDays="10" 19 | ) 20 | except ClientError as e: 21 | print "Domain already exists: ", e.response.get("Error", {}).get("Code") 22 | 23 | try: 24 | swf.register_workflow_type( 25 | domain=DOMAIN, 26 | name=WORKFLOW, 27 | version=VERSION, 28 | description="Test workflow", 29 | defaultExecutionStartToCloseTimeout="250", 30 | defaultTaskStartToCloseTimeout="NONE", 31 | defaultChildPolicy="TERMINATE", 32 | defaultTaskList={"name": TASKLIST} 33 | ) 34 | print "Test workflow created!" 35 | except ClientError as e: 36 | print "Workflow already exists: ", e.response.get("Error", {}).get("Code") 37 | 38 | try: 39 | swf.register_activity_type( 40 | domain=DOMAIN, 41 | name=TASKNAME, 42 | version=VERSION, 43 | description="Test worker", 44 | defaultTaskStartToCloseTimeout="NONE", 45 | defaultTaskList={"name": TASKLIST} 46 | ) 47 | print "Test worker created!" 48 | except ClientError as e: 49 | print "Activity already exists: ", e.response.get("Error", {}).get("Code") 50 | 51 | 52 | -------------------------------------------------------------------------------- /testdecider.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import boto3 4 | from botocore.client import Config 5 | import uuid 6 | 7 | botoConfig = Config(connect_timeout=50, read_timeout=70) 8 | swf = boto3.client('swf', config=botoConfig) 9 | 10 | DOMAIN = "yourtestdomain" 11 | WORKFLOW = "yourtestworkflow" 12 | TASKNAME = "yourtaskname" 13 | VERSION = "0.1" 14 | TASKLIST = "testlist" 15 | 16 | print "Listening for Decision Tasks" 17 | 18 | while True: 19 | 20 | newTask = swf.poll_for_decision_task( 21 | domain=DOMAIN, 22 | taskList={'name': TASKLIST}, 23 | identity='decider-1', 24 | reverseOrder=False) 25 | 26 | if 'taskToken' not in newTask: 27 | print "Poll timed out, no new task. Repoll" 28 | 29 | elif 'events' in newTask: 30 | 31 | eventHistory = [evt for evt in newTask['events'] if not evt['eventType'].startswith('Decision')] 32 | lastEvent = eventHistory[-1] 33 | 34 | if lastEvent['eventType'] == 'WorkflowExecutionStarted' and newTask['taskToken'] not in outstandingTasks: 35 | print "Dispatching task to worker", newTask['workflowExecution'], newTask['workflowType'] 36 | swf.respond_decision_task_completed( 37 | taskToken=newTask['taskToken'], 38 | decisions=[ 39 | { 40 | 'decisionType': 'ScheduleActivityTask', 41 | 'scheduleActivityTaskDecisionAttributes': { 42 | 'activityType':{ 43 | 'name': TASKNAME, 44 | 'version': VERSION 45 | }, 46 | 'activityId': 'activityid-' + str(uuid.uuid4()), 47 | 'input': '', 48 | 'scheduleToCloseTimeout': 'NONE', 49 | 'scheduleToStartTimeout': 'NONE', 50 | 'startToCloseTimeout': 'NONE', 51 | 'heartbeatTimeout': 'NONE', 52 | 'taskList': {'name': TASKLIST}, 53 | } 54 | } 55 | ] 56 | ) 57 | print "Task Dispatched:", newTask['taskToken'] 58 | 59 | elif lastEvent['eventType'] == 'ActivityTaskCompleted': 60 | swf.respond_decision_task_completed( 61 | taskToken=newTask['taskToken'], 62 | decisions=[ 63 | { 64 | 'decisionType': 'CompleteWorkflowExecution', 65 | 'completeWorkflowExecutionDecisionAttributes': { 66 | 'result': 'success' 67 | } 68 | } 69 | ] 70 | ) 71 | print "Task Completed!" 72 | 73 | 74 | 75 | --------------------------------------------------------------------------------