この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
AWS re:Invent 2016 Keynoteで発表された、ビジュアライズなワークフローを使用して、分散アプリケーションと Microservicesのコンポーネントを簡単にコーディネート出来るサービス『Step Functions』をAWS SDK for Python から使ってみます。
チュートリアル "Getting Started with AWS Step Functions" にある no-op な Pass ステートを利用したステートマシンを AWS SDK For Python から作成し、実行します。
Getting Started with AWS Step Functions - Developer Guide
AWS CLI向けは次の記事を参照下さい。
AWS Step FunctionsをAWS CLIから使ってみる #reinvent
1.ステートマシンの作成
ステートマシンの定義
"Type" が "Pass" の no-op なステートマシンを作成します。
JSON ベースの Amazon States Language でステートマシンを定義します。
definition.json
{
"Comment": "A Hello World example of the Amazon States Language using an AWS Lambda Function",
"StartAt": "HelloWorld",
"States": {
"HelloWorld": {
"Type": "Pass",
"Result": "Hello World!",
"End": true
}
}
}
ステートマシンの実行用 IAM ロール
ステートマシンの実行用に自動生成されたIAM Roleを指定します。 IAM Role の ARN を控えておいて下さい。
自動生成されたロールは以下のとおりです。 Step Function が Lambda を呼び出せるようになっていますが、今回は Lambda 連携は行いません。
Permissions
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"lambda:InvokeFunction"
],
"Resource": "*"
}
]
}
Trust Relationships
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "states.eu-west-1.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
ステートマシンの作成
最後の CreateStateMachine
API でステートマシンを作成します。
引数 | 意味 |
Name | ステートマシン名。リージョン毎にユニーク |
Definition | ステートマシンのAmazon States Languageによる定義 |
RoleArn | ステートマシンが利用するIAMロールのARN |
create_state_machine.py
import boto3
client = boto3.client('stepfunctions')
client.create_state_machine(
name="foo",
definition=open("definition.json").read(),
roleArn="arn:aws:iam::123456789012:role/service-role/StatesExecutionRole-eu-west-1"
)
RESPONSE
{'ResponseMetadata': {'HTTPHeaders': {'content-length': '109',
'content-type': 'application/x-amz-json-1.0',
'x-amzn-requestid': 'd72f1e08-c500-11e6-a0eb-016b0ac9b948'},
'HTTPStatusCode': 200,
'RequestId': 'd72f1e08-c500-11e6-a0eb-016b0ac9b948',
'RetryAttempts': 0},
u'creationDate': datetime.datetime(2016, 12, 18, 10, 3, 28, 295000, tzinfo=tzlocal()),
u'stateMachineArn': u'arn:aws:states:eu-west-1:123456789012:stateMachine:foo'}
作成したステートマシンを DescribeStateMachine
API で確認しましょう。
describe 対象は ステートマシンの ARN を指定します。
client.describe_state_machine(stateMachineArn='arn:aws:states:eu-west-1:123456789012:stateMachine:foo')
RESPONSE
{'ResponseMetadata': {'HTTPHeaders': {'content-length': '518',
'content-type': 'application/x-amz-json-1.0',
'x-amzn-requestid': '1cf27650-c501-11e6-a642-43c1a53708be'},
'HTTPStatusCode': 200,
'RequestId': '1cf27650-c501-11e6-a642-43c1a53708be',
'RetryAttempts': 0},
u'creationDate': datetime.datetime(2016, 12, 18, 10, 2, 17, 132000, tzinfo=tzlocal()),
u'definition': u'{\n "Comment": "A Hello World example of the Amazon States Language using an AWS Lambda Function",\n "StartAt": "HelloWorld",\n "States": {\n "HelloWorld": {\n "Type": "Pass",\n "Result": "Hello World!",\n "End": true\n }\n }\n}\n',
u'name': u'foo',
u'roleArn': u'arn:aws:iam::123456789012:role/service-role/StatesExecutionRole-eu-west-1',
u'stateMachineArn': u'arn:aws:states:eu-west-1:123456789012:stateMachine:foo',
u'status': u'ACTIVE'}
ListSateMachines
API を使うと、ステートマシン一覧を取得できます。
import boto3
client = boto3.client('stepfunctions')
client.list_state_machines()
RESPONSE
{'ResponseMetadata': {'HTTPHeaders': {'content-length': '265',
'content-type': 'application/x-amz-json-1.0',
'x-amzn-requestid': 'c60e66be-c4a1-11e6-a0c5-453e0e1f9c8f'},
'HTTPStatusCode': 200,
'RequestId': 'c60e66be-c4a1-11e6-a0c5-453e0e1f9c8f',
'RetryAttempts': 0},
u'stateMachines': [{u'creationDate': datetime.datetime(2016, 12, 17, 22, 41, 2, 537000, tzinfo=tzlocal()),
u'name': u'foo',
u'stateMachineArn': u'arn:aws:states:eu-west-1:123456789012:stateMachine:foo'},
{u'creationDate': datetime.datetime(2016, 12, 17, 22, 37, 14, 22000, tzinfo=tzlocal()),
u'name': u'foo2',
u'stateMachineArn': u'arn:aws:states:eu-west-1:123456789012:stateMachine:foo'}]}
2.ステートマシンの実行
作成したステートマシンを実行します。
実行用入力データを JSON で用意します。
input.json
{
"Comment": "Insert your JSON here"
}
ステートマシンは StartExecution
API で呼び出します。
import boto3
client = boto3.client('stepfunctions')
client.start_execution(
**{
'input' : open('input.json').read(),
'stateMachineArn' : 'arn:aws:states:eu-west-1:123456789012:stateMachine:foo'
}
)
RESPONSE
{u'startDate': datetime.datetime(2016, 12, 18, 10, 8, 10, 135000, tzinfo=tzlocal()), 'ResponseMetadata': {'RetryAttempts': 0, 'HTTPStatusCode': 200, 'RequestId': '7f297002-c501-11e6-aba3-974b2c19db6e', 'HTTPHeaders': {'x-amzn-requestid': '7f297002-c501-11e6-aba3-974b2c19db6e', 'content-length': '136', 'content-type': 'application/x-amz-json-1.0'}}, u'executionArn': u'arn:aws:states:eu-west-1:123456789012:execution:foo:28c88d3b-9d58-4d23-840d-34329fe1951e'}
本当は client.start_execution(input = open('input.json').read(), 'stateMachineArn' = 'XXX')
のようにしたいところですが、input
は Python のキーワードのため、引数で利用しようとするとシンタックスエラーになります。そのワークアラウンドとして、辞書形式で引数を渡します。
なお、インプットデータが不要なときは
client.start_execution(stateMachineArn='arn:aws:states:eu-west-1:123456789012:stateMachine:foo')
とスッキリ書けます。
引数 | 意味 |
StateMachineArn | ステートマシンのARN |
Name | 実行名。リージョン毎にユニーク。省略すると、サーバー側がユニークな名前を付与。 |
Input | ステートマシン実行用のインプット |
実行結果を確認します。
import boto3
client = boto3.client('stepfunctions')
client.describe_execution(
executionArn='arn:aws:states:eu-west-1:123456789012:execution:foo:1ef5b54a-e3d5-44c4-a83f-cdf8dd87059e'
)
RESPONSE
{'ResponseMetadata': {'HTTPHeaders': {'content-length': '346',
'content-type': 'application/x-amz-json-1.0',
'x-amzn-requestid': 'e916cbbc-c4a2-11e6-9ffd-2567445d8c02'},
'HTTPStatusCode': 200,
'RequestId': 'e916cbbc-c4a2-11e6-9ffd-2567445d8c02',
'RetryAttempts': 0},
u'executionArn': u'arn:aws:states:eu-west-1:123456789012:execution:foo:1ef5b54a-e3d5-44c4-a83f-cdf8dd87059e',
u'input': u'{}',
u'name': u'1ef5b54a-e3d5-44c4-a83f-cdf8dd87059e',
u'output': u'"Hello World!"',
u'startDate': datetime.datetime(2016, 12, 17, 22, 48, 37, 190000, tzinfo=tzlocal()),
u'stateMachineArn': u'arn:aws:states:eu-west-1:123456789012:stateMachine:foo',
u'status': u'SUCCEEDED',
u'stopDate': datetime.datetime(2016, 12, 17, 22, 48, 37, 312000, tzinfo=tzlocal())}
"status": "SUCCEEDED"
と実行が成功したことがわかります。
"output": "\"Hello World!\""
と JSON で定義したとおりのアウトプットとなっています。
AMC の下図にあるようなステートの遷移は GetExecutionHistory
API で取得します。
import boto3
client = boto3.client('stepfunctions')
client.get_execution_history(
executionArn='arn:aws:states:eu-west-1:123456789012:execution:foo:1ef5b54a-e3d5-44c4-a83f-cdf8dd87059e',
reverseOrder=False)
)
RESPONSE
{'ResponseMetadata': {'HTTPHeaders': {'content-length': '893',
'content-type': 'application/x-amz-json-1.0',
'x-amzn-requestid': '4cfc5fae-c4a3-11e6-8f47-99e5d3d2e683'},
'HTTPStatusCode': 200,
'RequestId': '4cfc5fae-c4a3-11e6-8f47-99e5d3d2e683',
'RetryAttempts': 0},
u'events': [{u'executionStartedEventDetails': {u'input': u'{}',
u'roleArn': u'arn:aws:iam::123456789012:role/service-role/StatesExecutionRole-eu-west-1'},
u'id': 1,
u'previousEventId': 0,
u'timestamp': datetime.datetime(2016, 12, 17, 22, 48, 37, 190000, tzinfo=tzlocal()),
u'type': u'ExecutionStarted'},
{u'id': 2,
u'previousEventId': 0,
u'stateEnteredEventDetails': {u'input': u'{}', u'name': u'HelloWorld'},
u'timestamp': datetime.datetime(2016, 12, 17, 22, 48, 37, 312000, tzinfo=tzlocal()),
u'type': u'PassStateEntered'},
{u'id': 3,
u'previousEventId': 2,
u'stateExitedEventDetails': {u'name': u'HelloWorld',
u'output': u'"Hello World!"'},
u'timestamp': datetime.datetime(2016, 12, 17, 22, 48, 37, 312000, tzinfo=tzlocal()),
u'type': u'PassStateExited'},
{u'executionSucceededEventDetails': {u'output': u'"Hello World!"'},
u'id': 4,
u'previousEventId': 3,
u'timestamp': datetime.datetime(2016, 12, 17, 22, 48, 37, 312000, tzinfo=tzlocal()),
u'type': u'ExecutionSucceeded'}]}
ListExecutions
API を使うと、ステートマシンの実行一覧を取得できます。
import boto3
client = boto3.client('stepfunctions')
client.list_executions(
stateMachineArn='arn:aws:states:eu-west-1:123456789012:stateMachine:foo'
)
RESPONSE
{'ResponseMetadata': {'HTTPHeaders': {'content-length': '323',
'content-type': 'application/x-amz-json-1.0',
'x-amzn-requestid': '06dad61b-c502-11e6-962a-27b1fe024b21'},
'HTTPStatusCode': 200,
'RequestId': '06dad61b-c502-11e6-962a-27b1fe024b21',
'RetryAttempts': 0},
u'executions': [{u'executionArn': u'arn:aws:states:eu-west-1:123456789012:execution:foo:28c88d3b-9d58-4d23-840d-34329fe1951e',
u'name': u'28c88d3b-9d58-4d23-840d-34329fe1951e',
u'startDate': datetime.datetime(2016, 12, 18, 10, 8, 10, 135000, tzinfo=tzlocal()),
u'stateMachineArn': u'arn:aws:states:eu-west-1:123456789012:stateMachine:foo',
u'status': u'SUCCEEDED',
u'stopDate': datetime.datetime(2016, 12, 18, 10, 8, 10, 182000, tzinfo=tzlocal())}]}
3. ステートマシンの削除
最後に作成したステートマシンを DeleteStateMachine
API で削除します。
import boto3
client = boto3.client('stepfunctions')
client.delete_state_machine(
stateMachineArn='arn:aws:states:eu-west-1:123456789012:stateMachine:foo'
)
RESPONSE
{'ResponseMetadata': {'HTTPHeaders': {'content-length': '2',
'content-type': 'application/x-amz-json-1.0',
'x-amzn-requestid': '578a70f2-c4a4-11e6-8779-db475dfb3ad2'},
'HTTPStatusCode': 200,
'RequestId': '578a70f2-c4a4-11e6-8779-db475dfb3ad2',
'RetryAttempts': 0}}
削除したステートマシンを describe すると "status" : "DELETING"
となっています。
import boto3
client = boto3.client('stepfunctions')
client.describe_state_machine(
stateMachineArn='arn:aws:states:eu-west-1:123456789012:stateMachine:foo'
)
RESPONSE
{'ResponseMetadata': {'HTTPHeaders': {'content-length': '520',
'content-type': 'application/x-amz-json-1.0',
'x-amzn-requestid': '82cce048-c502-11e6-b890-d946f76fd0d2'},
'HTTPStatusCode': 200,
'RequestId': '82cce048-c502-11e6-b890-d946f76fd0d2',
'RetryAttempts': 0},
u'creationDate': datetime.datetime(2016, 12, 18, 10, 14, 58, 828000, tzinfo=tzlocal()),
u'definition': u'{\n "Comment": "A Hello World example of the Amazon States Language using an AWS Lambda Function",\n "StartAt": "HelloWorld",\n "States": {\n "HelloWorld": {\n "Type": "Pass",\n "Result": "Hello World!",\n "End": true\n }\n }\n}\n',
u'name': u'foo',
u'roleArn': u'arn:aws:iam::123456789012:role/service-role/StatesExecutionRole-eu-west-1',
u'stateMachineArn': u'arn:aws:states:eu-west-1:123456789012:stateMachine:foo',
u'status': u'DELETING'}
しばらく待つと、ステートマシンの削除が完了します。
削除完了後に DescribeStateMachine
API を実行すると、次のように StateMachineDoesNotExist
エラーが発生します。
import boto3
client = boto3.client('stepfunctions')
client.describe_state_machine(
stateMachineArn='arn:aws:states:eu-west-1:123456789012:stateMachine:foo'
)
RESPONSE
ClientError: An error occurred (StateMachineDoesNotExist) when calling the DescribeStateMachine operation: State Machine Does Not Exist: 'arn:aws:states:eu-west-1:123456789012:stateMachine:foo'
まとめ
AWS Step Functions を AWS SDK for Python から使う方法を紹介しました。 何かのイベントをトリガーに Lambda 関数を呼び出し、Lambda 内から AWS Step Functions を呼び出すようなケースでは有用ではないかと思います。