{ "cells": [ { "cell_type": "markdown", "source": [ "# Magic Task\n", "\n", "## What is Magic Task\n", "\n", "The nature of the Amazon State Machine Definition is just a JSON DSL (Domain specific language). It uses special syntax like ``InputPath``, ``Parameters``, ``ResultSelector``, ``ResultPath``, ``OutputPath`` and ``ChoiceRule`` to provide basic capability to allow you to manipulate input / output data, make conditional choice. The research on user community shows that \"Input/Output data handling\" and \"Conditional Choice\" are difficult to learn and also not flexible to use.\n", "\n", "**Magic Task** is a feature in ``aws-stepfunction`` library that allows developer to implement \"Input/Output data handling\" and \"Conditional Choice\" in pure python function, and automatically creates the backend lambda function and hook up your tasks. With **Magic Task**, you no longer need to write ``JSON notation`` and ``ChoiceRule`` at all, instead, you just write your python code.\n", "\n", "**Example**\n", "\n", "This is an example from [official doc](https://docs.aws.amazon.com/step-functions/latest/dg/input-output-inputpath-params.html):\n", "\n", "State Input:\n", "\n", "```python\n", "{\n", " \"comment\": \"Example for InputPath.\",\n", " \"dataset1\": {\n", " \"val1\": 1,\n", " \"val2\": 2,\n", " \"val3\": 3\n", " },\n", " \"dataset2\": {\n", " \"val1\": \"a\",\n", " \"val2\": \"b\",\n", " \"val3\": \"c\"\n", " }\n", "}\n", "```\n", "\n", "``InputPath``:\n", "\n", "```python\n", "{\n", " \"InputPath\": \"$.dataset2\"\n", "}\n", "```\n", "\n", "With the previous InputPath, the following is the JSON that is passed as the input.\n", "\n", "```python\n", "{\n", " \"val1\": \"a\",\n", " \"val2\": \"b\",\n", " \"val3\": \"c\"\n", "}\n", "```\n", "\n", "**With Magic Task**\n", "\n", "You just need to write:\n", "\n", "```python\n", "def lambda_handler(event, context):\n", " return event[\"dataset2\"]\n", "```\n", "\n", "Of course, you can add data schema definition to improve readability:\n", "\n", "```python\n", "import dataclasses\n", "\n", "\n", "@dataclasses.dataclass\n", "class InputData:\n", " comment: str\n", " dataset1: dict\n", " dataset2: dict\n", "\n", "\n", "@dataclasses.dataclass\n", "class OutputData:\n", " val1: str\n", " val2: str\n", " val3: str\n", "\n", "\n", "def lambda_handler(event, context):\n", " input_data = InputData(**event)\n", " output_data = OutputData(**input_data.dataset2)\n", " return dataclasses.asdict(output_data)\n", "```\n", "\n", "\n", "Reference:\n", "\n", "- [Input Output Filtering](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-input-output-filtering.html)\n", "- [Choice](https://docs.aws.amazon.com/step-functions/latest/dg/amazon-states-language-choice-state.html)" ], "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } } }, { "cell_type": "markdown", "source": [ "## Learn Magic Task from Example\n", "\n", "Consider the following E-Shop Order Processing use case. When a customer placed an order, we need to do these in sequence:\n", "\n", "1. generate an order details\n", "2. go to item catalog to get the price and calculate total price for items\n", "3. go to shipment catalog to get the shipment cost\n", "4. #2 and #3 can do in parallel\n", "5. add up all cost together, find the final balance of the order\n", "6. process the payment for the order\n", "\n", "Below is a classic State Machine definition for this workflow. You have to use the ``InputPath``, ``Parameter`` etc ..., in task definition to implement how do you want to pass the data from one state to another.\n", "\n", "![E-Shop-Order-Processing-1](./E-Shop-Order-Processing-1.png)\n", "\n", "With **Magic Task**, you just need to write pure Python function to implement the data handling logic, and it will automatically become concrete Lambda Functions that are managed by ``aws_stepfunction`` library, without worry about deployment.\n", "\n", "For better communication, let's use these terminologies to\n", "\n", "1. **Business Logic Task** (in orange), a lambda function task that focus on processing the business logic.\n", "2. **Data Handling Task** (in red), a lambda function task that doesn't do any business logic, but just manipulating the data and hook up two Business Logic Tasks.\n", "\n", "![E-Shop-Order-Processing-2](./E-Shop-Order-Processing-2.png)\n", "\n", "First, let's import required libraries" ], "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } } }, { "cell_type": "code", "execution_count": 4, "outputs": [], "source": [ "import os\n", "import json\n", "\n", "from pathlib_mate import Path\n", "import aws_stepfunction as sfn\n", "from aws_stepfunction.magic import LambdaTask\n", "\n", "from boto_session_manager import BotoSesManager\n", "from rich import print as rprint\n", "\n", "dir_here = Path(os.getcwd()).absolute()\n", "\n", "bsm = BotoSesManager(\n", " profile_name=\"aws_data_lab_sanhe_us_east_1\",\n", " region_name=\"us-east-1\",\n", ")" ], "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } } }, { "cell_type": "markdown", "source": [ "### Use Magic Task to create \"Business Logic Task\"\n", "\n", "First we would like to prepare the \"Business Logic Task\". ``aws_stepfunction`` provide a special ``LambdaTask`` state. It represents a Lambda Function that managed (Create / Update / Delete) by the state machine. In this example, we want to skip the effort to set up the \"Business Logic Task\" Lambda Function, and would like to let the ``aws_stepfunction`` library to take the heavy lifting.\n", "\n", "Here's the scripts:\n", "\n", "- [Task1 Get Order Detail](./script.html#task1-get-order-detail)\n", "- [Task2a 2 Get Item Cost](./script.html#task2a-2-get-item-cost)\n", "- [Task2b 2 Get Ship Cost](./script.html#task2b-2-get-ship-cost)\n", "- [Task4 Process Payment](./script.html#task4-process-payment)\n", "\n", "Limitation:\n", "\n", "- It has to be single file python script.\n", "- Only has standard library and boto3 related libraries.\n", "- NOTE: we plan to add third party libraries support soon.\n" ], "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } } }, { "cell_type": "code", "execution_count": 6, "outputs": [], "source": [ "task1_get_order_detail = LambdaTask(\n", " id=\"Task1-Get-Order-Detail\",\n", " lbd_func_name=\"aws_stepfunction_magic_task_demo-task1_get_order_detail\",\n", " lbd_package=\"s1_get_order_detail.py\",\n", " lbd_handler=\"s1_get_order_detail.lambda_handler\",\n", " lbd_aws_account_id=bsm.aws_account_id,\n", " lbd_aws_region=bsm.aws_region,\n", ")\n", "\n", "task2a_2_get_item_cost = LambdaTask(\n", " id=\"Task2a-2-Get-Item-Cost\",\n", " lbd_func_name=\"aws_stepfunction_magic_task_demo-task2a_2_get_item_cost\",\n", " lbd_package=\"s2a_2_get_item_cost.py\",\n", " lbd_handler=\"s2a_2_get_item_cost.lambda_handler\",\n", " lbd_aws_account_id=bsm.aws_account_id,\n", " lbd_aws_region=bsm.aws_region,\n", ")\n", "\n", "task2b_2_get_ship_cost = LambdaTask(\n", " id=\"Task2b-2-Get-Ship-Cost\",\n", " lbd_func_name=\"aws_stepfunction_magic_task_demo-task2b_2_get_ship_cost\",\n", " lbd_package=\"s2b_2_get_ship_cost.py\",\n", " lbd_handler=\"s2b_2_get_ship_cost.lambda_handler\",\n", " lbd_aws_account_id=bsm.aws_account_id,\n", " lbd_aws_region=bsm.aws_region,\n", ")\n", "\n", "task4_process_payment = LambdaTask(\n", " id=\"Task4-Process-Payment\",\n", " lbd_func_name=\"aws_stepfunction_magic_task_demo-task4_process_payment\",\n", " lbd_package=\"s4_process_payment.py\",\n", " lbd_handler=\"s4_process_payment.lambda_handler\",\n", " lbd_aws_account_id=bsm.aws_account_id,\n", " lbd_aws_region=bsm.aws_region,\n", ")" ], "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } } }, { "cell_type": "markdown", "source": [ "### Use Magic Task to create \"Data Handling Task\"\n", "\n", "Then we can use **Magic Task** ``LambdaTask`` class to create three data handling lambda functions:\n", "\n", "- Use ``Task2a 1 Extract Items`` to hook up ``Task1 Get Order Detail`` and ``Task2a 2 Get Item Cost``.\n", "- Use ``Task2b 1 Extract Ship Address`` to hook up ``Task1 Get Order Detail`` and ``Task2b 2 Get Ship Cost``.\n", "- Use ``Task3 Find Balance`` to hook up both ``Task2a 2 Get Item Cost`` and ``Task2b 2 Get Ship Cost`` with the final ``Task4 Process Payment``\n", "\n", "Here's the scripts:\n", "\n", "- [Task2a 1 Extract Items](./script.html#task2a-1-extract-items)\n", "- [Task2b 1 Extract Ship Address](./script.html#task2b-1-extract-ship-address)\n", "- [Task3 Find Balance](./script.html#task3-find-balance)" ], "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } } }, { "cell_type": "code", "execution_count": 7, "outputs": [], "source": [ "task2a_1_extract_items = LambdaTask(\n", " id=\"Task2a-1-Extract-Items\",\n", " lbd_func_name=\"aws_stepfunction_magic_task_demo-task2a_1_extract_items\",\n", " lbd_package=\"s2a_1_extract_items.py\",\n", " lbd_handler=\"s2a_1_extract_items.lambda_handler\",\n", " lbd_aws_account_id=bsm.aws_account_id,\n", " lbd_aws_region=bsm.aws_region,\n", ")\n", "\n", "task2b_1_extract_ship_address = LambdaTask(\n", " id=\"Task2b-1-Extract-Ship-Address\",\n", " lbd_func_name=\"aws_stepfunction_magic_task_demo-task2b_1_extract_ship_address\",\n", " lbd_package=\"s2b_1_extract_ship_address.py\",\n", " lbd_handler=\"s2b_1_extract_ship_address.lambda_handler\",\n", " lbd_aws_account_id=bsm.aws_account_id,\n", " lbd_aws_region=bsm.aws_region,\n", ")\n", "\n", "task3_find_balance = LambdaTask(\n", " id=\"Task3-Find-Balance\",\n", " lbd_func_name=\"aws_stepfunction_magic_task_demo-task3_find_balance\",\n", " lbd_package=\"s3_find_balance.py\",\n", " lbd_handler=\"s3_find_balance.lambda_handler\",\n", " lbd_aws_account_id=bsm.aws_account_id,\n", " lbd_aws_region=bsm.aws_region,\n", ")" ], "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } } }, { "cell_type": "markdown", "source": [], "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } } }, { "cell_type": "code", "execution_count": 9, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "preview workflow definition\n", "{\n", " \"StartAt\": \"Task1-Get-Order-Detail\",\n", " \"States\": {\n", " \"Task1-Get-Order-Detail\": {\n", " \"Type\": \"Task\",\n", " \"Resource\": \"arn:aws:states:::lambda:invoke\",\n", " \"Next\": \"Parallel-after-Task1-Get-Order-Detail\",\n", " \"Parameters\": {\n", " \"Payload.$\": \"$\",\n", " \"FunctionName\": \"arn:aws:lambda:us-east-1:669508176277:function:aws_stepfunction_magic_task_demo-task1_get_order_detail\"\n", " },\n", " \"OutputPath\": \"$.Payload\",\n", " \"Retry\": [\n", " {\n", " \"ErrorEquals\": [\n", " \"Lambda.ServiceException\",\n", " \"Lambda.AWSLambdaException\",\n", " \"Lambda.SdkClientException\"\n", " ],\n", " \"IntervalSeconds\": 2,\n", " \"BackoffRate\": 2,\n", " \"MaxAttempts\": 3\n", " }\n", " ]\n", " },\n", " \"Parallel-after-Task1-Get-Order-Detail\": {\n", " \"Type\": \"Parallel\",\n", " \"Branches\": [\n", " {\n", " \"StartAt\": \"Task2a-1-Extract-Items\",\n", " \"States\": {\n", " \"Task2a-1-Extract-Items\": {\n", " \"Type\": \"Task\",\n", " \"Resource\": \"arn:aws:states:::lambda:invoke\",\n", " \"Next\": \"Task2a-2-Get-Item-Cost\",\n", " \"Parameters\": {\n", " \"Payload.$\": \"$\",\n", " \"FunctionName\": \"arn:aws:lambda:us-east-1:669508176277:function:aws_stepfunction_magic_task_demo-task2a_1_extract_items\"\n", " },\n", " \"OutputPath\": \"$.Payload\",\n", " \"Retry\": [\n", " {\n", " \"ErrorEquals\": [\n", " \"Lambda.ServiceException\",\n", " \"Lambda.AWSLambdaException\",\n", " \"Lambda.SdkClientException\"\n", " ],\n", " \"IntervalSeconds\": 2,\n", " \"BackoffRate\": 2,\n", " \"MaxAttempts\": 3\n", " }\n", " ]\n", " },\n", " \"Task2a-2-Get-Item-Cost\": {\n", " \"Type\": \"Task\",\n", " \"Resource\": \"arn:aws:states:::lambda:invoke\",\n", " \"End\": true,\n", " \"Parameters\": {\n", " \"Payload.$\": \"$\",\n", " \"FunctionName\": \"arn:aws:lambda:us-east-1:669508176277:function:aws_stepfunction_magic_task_demo-task2a_2_get_item_cost\"\n", " },\n", " \"OutputPath\": \"$.Payload\",\n", " \"Retry\": [\n", " {\n", " \"ErrorEquals\": [\n", " \"Lambda.ServiceException\",\n", " \"Lambda.AWSLambdaException\",\n", " \"Lambda.SdkClientException\"\n", " ],\n", " \"IntervalSeconds\": 2,\n", " \"BackoffRate\": 2,\n", " \"MaxAttempts\": 3\n", " }\n", " ]\n", " }\n", " }\n", " },\n", " {\n", " \"StartAt\": \"Task2b-1-Extract-Ship-Address\",\n", " \"States\": {\n", " \"Task2b-1-Extract-Ship-Address\": {\n", " \"Type\": \"Task\",\n", " \"Resource\": \"arn:aws:states:::lambda:invoke\",\n", " \"Next\": \"Task2b-2-Get-Ship-Cost\",\n", " \"Parameters\": {\n", " \"Payload.$\": \"$\",\n", " \"FunctionName\": \"arn:aws:lambda:us-east-1:669508176277:function:aws_stepfunction_magic_task_demo-task2b_1_extract_ship_address\"\n", " },\n", " \"OutputPath\": \"$.Payload\",\n", " \"Retry\": [\n", " {\n", " \"ErrorEquals\": [\n", " \"Lambda.ServiceException\",\n", " \"Lambda.AWSLambdaException\",\n", " \"Lambda.SdkClientException\"\n", " ],\n", " \"IntervalSeconds\": 2,\n", " \"BackoffRate\": 2,\n", " \"MaxAttempts\": 3\n", " }\n", " ]\n", " },\n", " \"Task2b-2-Get-Ship-Cost\": {\n", " \"Type\": \"Task\",\n", " \"Resource\": \"arn:aws:states:::lambda:invoke\",\n", " \"End\": true,\n", " \"Parameters\": {\n", " \"Payload.$\": \"$\",\n", " \"FunctionName\": \"arn:aws:lambda:us-east-1:669508176277:function:aws_stepfunction_magic_task_demo-task2b_2_get_ship_cost\"\n", " },\n", " \"OutputPath\": \"$.Payload\",\n", " \"Retry\": [\n", " {\n", " \"ErrorEquals\": [\n", " \"Lambda.ServiceException\",\n", " \"Lambda.AWSLambdaException\",\n", " \"Lambda.SdkClientException\"\n", " ],\n", " \"IntervalSeconds\": 2,\n", " \"BackoffRate\": 2,\n", " \"MaxAttempts\": 3\n", " }\n", " ]\n", " }\n", " }\n", " }\n", " ],\n", " \"Next\": \"Task3-Find-Balance\"\n", " },\n", " \"Task3-Find-Balance\": {\n", " \"Type\": \"Task\",\n", " \"Resource\": \"arn:aws:states:::lambda:invoke\",\n", " \"Next\": \"Task4-Process-Payment\",\n", " \"Parameters\": {\n", " \"Payload.$\": \"$\",\n", " \"FunctionName\": \"arn:aws:lambda:us-east-1:669508176277:function:aws_stepfunction_magic_task_demo-task3_find_balance\"\n", " },\n", " \"OutputPath\": \"$.Payload\",\n", " \"Retry\": [\n", " {\n", " \"ErrorEquals\": [\n", " \"Lambda.ServiceException\",\n", " \"Lambda.AWSLambdaException\",\n", " \"Lambda.SdkClientException\"\n", " ],\n", " \"IntervalSeconds\": 2,\n", " \"BackoffRate\": 2,\n", " \"MaxAttempts\": 3\n", " }\n", " ]\n", " },\n", " \"Task4-Process-Payment\": {\n", " \"Type\": \"Task\",\n", " \"Resource\": \"arn:aws:states:::lambda:invoke\",\n", " \"End\": true,\n", " \"Parameters\": {\n", " \"Payload.$\": \"$\",\n", " \"FunctionName\": \"arn:aws:lambda:us-east-1:669508176277:function:aws_stepfunction_magic_task_demo-task4_process_payment\"\n", " },\n", " \"OutputPath\": \"$.Payload\",\n", " \"Retry\": [\n", " {\n", " \"ErrorEquals\": [\n", " \"Lambda.ServiceException\",\n", " \"Lambda.AWSLambdaException\",\n", " \"Lambda.SdkClientException\"\n", " ],\n", " \"IntervalSeconds\": 2,\n", " \"BackoffRate\": 2,\n", " \"MaxAttempts\": 3\n", " }\n", " ]\n", " }\n", " }\n", "}\n" ] } ], "source": [ "workflow = sfn.Workflow()\n", "(\n", " workflow.start_from(task1_get_order_detail)\n", " .parallel([\n", " (\n", " workflow.subflow_from(task2a_1_extract_items)\n", " .next_then(task2a_2_get_item_cost)\n", " .end()\n", " ),\n", " (\n", " workflow.subflow_from(task2b_1_extract_ship_address)\n", " .next_then(task2b_2_get_ship_cost)\n", " .end()\n", " ),\n", " ])\n", " .next_then(task3_find_balance)\n", " .next_then(task4_process_payment)\n", " .end()\n", ")\n", "\n", "print(\"preview workflow definition\")\n", "print(json.dumps(workflow.serialize(), indent=4))" ], "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } } }, { "cell_type": "markdown", "source": [ "### Deploy a State Machine to AWS\n", "\n", "Now, let's deploy the State Machine and all necessary Magic Lambda Functions and also includes default S3 Bucket (to store lambda deployment artifacts) and IAM Role (for basic lambda execution role)." ], "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } } }, { "cell_type": "code", "execution_count": 10, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "detect whether the magic task is used ...\n", " yes\n", "identify necessary S3 bucket and IAM role ...\n", " need to create S3 Bucket '669508176277-us-east-1-aws-stepfunction-python-sdk'\n", " we need a default IAM role for lambda function\n", " need to create IAM Role 'aws-stepfunction-python-sdk-magic-task-role'\n", " done\n", "deploy S3 and IAM ...\n", " preview cloudformation stack status: https://console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks?filteringStatus=active&filteringText=aws-stepfunction-magic-task-demo&viewNested=true&hideStacks=false&stackId=\n", "wait 'aws-stepfunction-magic-task-demo' stack to complete ... \n", " elapsed 0 seconds ...\n", " elapsed 5 seconds ...\n", " elapsed 10 seconds ...\n", " elapsed 15 seconds ...\n", " elapsed 20 seconds ...\n", " elapsed 25 seconds ...\n", " done\n", "deploy Lambda Functions ...\n", " upload lambda deployment artifacts ...\n", " upload from /Users/sanhehu/tmp/15598fc58f34fc1f96961b2ac2bfa8d4.zip to s3://669508176277-us-east-1-aws-stepfunction-python-sdk/aws-stepfunction-python-sdk/a545c26c83561866d4aba791976948d8.zip\n", " declare Lambda Function aws_stepfunction_magic_task_demo-task1_get_order_detail\n", " upload from /Users/sanhehu/tmp/e80c5b01037301fc9fc7505d74c5ff91.zip to s3://669508176277-us-east-1-aws-stepfunction-python-sdk/aws-stepfunction-python-sdk/9c6078c9a0ed07b904b21dc8e710bebd.zip\n", " declare Lambda Function aws_stepfunction_magic_task_demo-task2a_1_extract_items\n", " upload from /Users/sanhehu/tmp/fa760dbc90fabef2e87d6513173ce8d9.zip to s3://669508176277-us-east-1-aws-stepfunction-python-sdk/aws-stepfunction-python-sdk/b4077b1decf3da0ca2102077745c1d73.zip\n", " declare Lambda Function aws_stepfunction_magic_task_demo-task2a_2_get_item_cost\n", " upload from /Users/sanhehu/tmp/000dc7fe1ad3d583858d410068f75c6b.zip to s3://669508176277-us-east-1-aws-stepfunction-python-sdk/aws-stepfunction-python-sdk/4ebd33b4da1e2dca0e2338b22ec4164f.zip\n", " declare Lambda Function aws_stepfunction_magic_task_demo-task2b_1_extract_ship_address\n", " upload from /Users/sanhehu/tmp/009d9755c81982f704e9ac16aee18c5a.zip to s3://669508176277-us-east-1-aws-stepfunction-python-sdk/aws-stepfunction-python-sdk/bd0ae3f3dc396dac10a3bd61511bcddf.zip\n", " declare Lambda Function aws_stepfunction_magic_task_demo-task2b_2_get_ship_cost\n", " upload from /Users/sanhehu/tmp/fd78f0b11843a3b1b66551709b750844.zip to s3://669508176277-us-east-1-aws-stepfunction-python-sdk/aws-stepfunction-python-sdk/c3b94e8b6666b94610f163818efdd567.zip\n", " declare Lambda Function aws_stepfunction_magic_task_demo-task3_find_balance\n", " upload from /Users/sanhehu/tmp/1d8e921ecf9d9e39751575d141476cbf.zip to s3://669508176277-us-east-1-aws-stepfunction-python-sdk/aws-stepfunction-python-sdk/6a5f3157ee87d81c9a1a5baf4a43fb74.zip\n", " declare Lambda Function aws_stepfunction_magic_task_demo-task4_process_payment\n", "deploy magic task Lambda Function ...\n", " preview cloudformation stack status: https://console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks?filteringStatus=active&filteringText=aws-stepfunction-magic-task-demo&viewNested=true&hideStacks=false&stackId=\n", "wait 'aws-stepfunction-magic-task-demo' stack to complete ... \n", " elapsed 0 seconds ...\n", " elapsed 5 seconds ...\n", " elapsed 10 seconds ...\n", " elapsed 15 seconds ...\n", " done\n", "deploy state machine to 'arn:aws:states:us-east-1:669508176277:stateMachine:aws_stepfunction_magic_task_demo' ...\n", " not exists, create state machine ...\n", " done, preview at: https://us-east-1.console.aws.amazon.com/states/home?region=us-east-1#/visual-editor?stateMachineArn=arn:aws:states:us-east-1:669508176277:stateMachine:aws_stepfunction_magic_task_demo\n" ] } ], "source": [ "sfn_name = \"aws_stepfunction_magic_task_demo\"\n", "\n", "state_machine = sfn.StateMachine(\n", " name=sfn_name,\n", " workflow=workflow,\n", " role_arn=\"arn:aws:iam::669508176277:role/sanhe-for-everything-admin\",\n", ")\n", "state_machine.set_type_as_express()\n", "\n", "deploy_result = state_machine.deploy(bsm, verbose=True)" ], "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } } }, { "cell_type": "markdown", "source": [ "You can click the preview link to see the workflow definition in Canvas\n", "\n", "![e-shop-order-processing-workflow](./e-shop-order-processing-workflow.png)" ], "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } } }, { "cell_type": "markdown", "source": [ "### Execute the State Machine with Custom Input Data\n", "\n", "You can run your state machine with custom input data and see the output data immediately." ], "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } } }, { "cell_type": "code", "execution_count": 11, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "execute state machine 'arn:aws:states:us-east-1:669508176277:stateMachine:aws_stepfunction_magic_task_demo'\n", " preview at: https://us-east-1.console.aws.amazon.com/states/home?region=us-east-1#/express-executions/details/arn:aws:states:us-east-1:669508176277:express:aws_stepfunction_magic_task_demo:34c29e53-13df-43d1-b859-6c527da193e8:6452de94-c837-45f5-8df2-8b6f6484e6a6?startDate=1668018377096\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "input:\n", "\n", "{\"order_id\": \"order-1\"}\n", "\n", "output:\n", "\n", "{\"status\": \"success\"}\n" ] } ], "source": [ "execute_result = state_machine.execute(\n", " bsm,\n", " payload={\"order_id\": \"order-1\"},\n", " sync=True,\n", ")\n", "\n", "input = json.loads(execute_result[\"input\"])\n", "output = json.loads(execute_result[\"output\"])\n", "print(f\"\\ninput:\\n\")\n", "print(json.dumps(input))\n", "print(f\"\\noutput:\\n\")\n", "print(json.dumps(output))" ], "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } } }, { "cell_type": "markdown", "source": [ "You can just click the link to preview the result and also intermediate data in a nice GUI.\n", "\n", "![execute-result](./execute-result.png)" ], "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } } }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [], "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } } } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.6" } }, "nbformat": 4, "nbformat_minor": 0 }