目的
AWSでサーバーインスタンス起動系などのリクエストをすると数分待つことになります。
対象や実現方法は色々考えられますが、今回はRedshiftを起動し、使える状態になるまで待機する部分をAWS Step Functionsで実装してみます。
概要
- チュートリアルのターゲットをRedshiftに変えて実際にやってみたという内容です。
- LambdaはPython3.6で記述します。
手順
- 実行用のロールや環境設定は省略します
Redshift起動Lambdaを作成
createRedshiftCluster
という名前でLambda Functionを作成します。
パラメータはハードコーディングになっています。(記事用にシンプルにするためです 汗)
import boto3
def lambda_handler(event, context):
redshift = boto3.client('redshift')
redshift.create_cluster(
ClusterIdentifier='test-cluster',
DBName='dev',
Port=5439,
MasterUsername='testuser',
MasterUserPassword='myPassword1234',
VpcSecurityGroupIds=['sg-abcdef12'],
ClusterSubnetGroupName='csg1',
NodeType='dc2.large',
ClusterType='single-node',
PubliclyAccessible=True,
EnhancedVpcRouting=False)
event['result'] = 'SUCCESS'
return event
Redshift起動完了確認Lambdaを作成
waitRedshift
という名前でLambda Functionを作成します。
WaiterAPIを利用しますがここではリトライはしません。(MaxAttempts=1は1回実行して実行中なら再試行しません)
StepFunctions側でリトライを制御します。
エラー処理は微妙かもしれません。現物合わせです。
起動中ならCREATING
、準備完了なら RUNNING
を返すようにしてあります。
import boto3
import botocore
def lambda_handler(event, context):
redshift = boto3.client('redshift')
waiter = redshift.get_waiter('cluster_available')
try:
waiter.wait(
ClusterIdentifier='test-cluster',
WaiterConfig={
'Delay': 3,
'MaxAttempts': 1})
event['result'] = 'RUNNING'
except botocore.exceptions.WaiterError as e:
if not hasattr(e, 'last_response'):
raise e
if 'Error' in e.last_response:
raise e
event['result'] = 'CREATING'
return event
全体の流れをStepFunctionsで作成
PrepareRedshift
という名前でStepFunctionsを作成します。
上記で作成した lambda:createRedshiftCluster
を実行し、20秒待ち。
lambda:waitRedshift
で完了チェックし、まだなら再度20秒待ち。これを繰り返します。
APIコール部分はリトライも記述してあります。
{
"Comment": "Create and Wait for Redshift Cluster",
"StartAt": "CreateCluster",
"States": {
"CreateCluster": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:createRedshiftCluster",
"Next": "Wait",
"Retry": [
{
"ErrorEquals": ["States.ALL"],
"IntervalSeconds": 5,
"MaxAttempts": 3,
"BackoffRate": 2.0
}
]
},
"Wait": {
"Type": "Wait",
"Seconds" : 20,
"Next": "CheckStatus"
},
"CheckStatus": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:waitRedshift",
"Next": "IsRunning",
"Retry": [
{
"ErrorEquals": ["States.ALL"],
"IntervalSeconds": 5,
"MaxAttempts": 3,
"BackoffRate": 2.0
}
]
},
"IsRunning": {
"Type": "Choice",
"Choices": [
{
"Variable": "$.result",
"StringEquals": "RUNNING",
"Next": "Success"
},
{
"Variable": "$.result",
"StringEquals": "CREATING",
"Next": "Wait"
}
],
"Default": "Abort"
},
"Abort": {
"Type": "Fail"
},
"Success": {
"Type": "Succeed"
}
}
}
記述について
素晴らしい機能ですが、Amazon States Language なる言語(?)で記述する必要があります。
あとフロー中の変数取り回しができるのですが、 $.var
のような記述でこれはJsonPathというようです。
ちょっと大変ですが、ひと通り目を通しておいたほうが良さそうです。
ビジュアライズしてくれるのでそこはホッとします。
表示例:(Endがつながっていませんが大丈夫です )
実行結果
マネージメントコンソールから実行すると実行中、実行終了のステップに着色されていきます。
今回は4分ほどで成功しました。
まとめ
Redshiftクラスタが操作可能になるまで待機する、というパーツはできました。(※エラー処理とかテストとか全然できてませんが )
現実的には、処理の起動トリガーをどうするか、後続処理を実装する等、システムとして組み立てることになると思います。
プロジェクトとしては、いわゆるビジネスロジック(古い表現かも)部分に時間を掛けたいはずですよね。
今回のような準備処理は時間をかけず、サラリと実現するためのツールが Cloud Automatorですねー