Serverless FrameworkでStep Functionsを扱ってみる

この記事はServerless Advent Calendar 2017の24日目に遅刻した記事です。 AWS Step Functions AWS Lambda 1つで完了できないようなタスク・ワークフローをいい感じに […]

広告ここから
広告ここまで

目次

    この記事はServerless Advent Calendar 2017の24日目に遅刻した記事です。

    AWS Step Functions

    AWS Lambda 1つで完了できないようなタスク・ワークフローをいい感じに処理できるようにするやつ(という適当な認識)なAWS Step Functions。

    使ってみたいなと思いつつなかなか使う機会がなかったので、これを機に触ってみました。

    GUIで設定はしたくない

    チュートリアルなどは基本的にGUIでポチポチやるスタイルですが、terraformやCloudFormation、Serverless Frameworkに慣れてくるとコードで定義したくなります。

    ということで堀家さんのプラグイン、Serverless Step FunctionsをServerless Frameworkに入れて立ち上げるようにします。

    プロジェクトのセットアップ

    とりあえずServerless Frameworkを使ったプロジェクトでやるいつもの手順。

    $ serverless create -t aws-nodejs -p step-functions
    Serverless: Generating boilerplate...
    Serverless: Generating boilerplate in "/Users/dc_hideokamoto/develop/node/sls/step-functions"
     _______                             __
    |   _   .-----.----.--.--.-----.----|  .-----.-----.-----.
    |   |___|  -__|   _|  |  |  -__|   _|  |  -__|__ --|__ --|
    |____   |_____|__|  \___/|_____|__| |__|_____|_____|_____|
    |   |   |             The Serverless Application Framework
    |       |                           serverless.com, v1.21.1
     -------'
    
    Serverless: Successfully generated boilerplate for template: "aws-nodejs"
    
    $ git init && npm init -y
    Initialized empty Git repository in /node/sls/step-functions/.git/
    Wrote to /node/sls/step-functions/package.json:
    
    {
      "name": "step-functions",
      "version": "1.0.0",
      "description": "",
      "main": "handler.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "keywords": [],
      "author": "",
      "license": "ISC"
    }
    
    

    Serverless Step Functionsプラグインのインストール

    Serverless Frameworkのプラグインとして配布されていますので、インストールとセットアップを進めます。

    $ npm install --save-dev serverless-step-functions
    

    serverless.ymlにもプラグインを使用することを明記しましょう。

    service: sls-step-functions-example
    
    provider:
      name: aws
      runtime: nodejs6.10
    
    functions:
      hello:
        handler: handler.hello
    
    plugins:
      - serverless-step-functions
    

    これで準備OKです。

    プロジェクトをデプロイする

    ドキュメントを見る限り、StateMachineの定義でLambdaのARNが必要になる様子です。

    serverless.ymlの中で値を引き回す方法があるのかもですが、ちょっと調べきれてないので今回は一旦Lambdaを先にデプロイして決めうちで書くやり方をとります。

    $ sls deploy
    Serverless: Packaging service...
    Serverless: Excluding development dependencies...
    Serverless: Creating Stack...
    Serverless: Checking Stack create progress...
    .....
    Serverless: Stack create finished...
    Serverless: Uploading CloudFormation file to S3...
    Serverless: Uploading artifacts...
    Serverless: Uploading service .zip file to S3 (3.49 KB)...
    Serverless: Validating template...
    Serverless: Updating Stack...
    Serverless: Checking Stack update progress...
    ..................
    Serverless: Stack update finished...
    Service Information
    service: sls-step-functions-example
    stage: dev
    region: us-east-1
    stack: sls-step-functions-example-dev
    api keys:
      None
    endpoints:
      None
    functions:
      hello: sls-step-functions-example-dev-hello
    Serverless StepFunctions OutPuts
    endpoints:
    
    

    ちゃんと動作してくれています。

    $ sls invoke -f hello
    {
        "statusCode": 200,
        "body": "{\"message\":\"Go Serverless v1.0! Your function executed successfully!\",\"input\":{}}"
    }
    

    LambdaのARNはAWS-CLIからとりました。

    $ aws lambda list-functions | grep sls-step-functions-example-dev-hello
                "FunctionName": "sls-step-functions-example-dev-hello", 
                "FunctionArn": "arn:aws:lambda:us-east-1:9999999999:function:sls-step-functions-example-dev-hello",
    

    FunctionArnの値を控えたら、serverless.ymlに以下の項目を追加します。

    stepFunctions:
      stateMachines:
        hellostepfunc1:
          name: myStateMachine
          definition:
            Comment: "A Hello World example of the Amazon States Language using an AWS Lambda Function"
            StartAt: HelloWorld1
            States:
              HelloWorld1:
                Type: Task
                Resource: arn:aws:lambda:#{AWS::Region}:#{AWS::AccountId}:function:${self:service}-${opt:stage}-hello
                End: true
    

    この状態でデプロイすると、最初のStep Functionsが作成されます。

    $ sls deploy
    Serverless: Packaging service...
    Serverless: Excluding development dependencies...
    Serverless: Uploading CloudFormation file to S3...
    Serverless: Uploading artifacts...
    Serverless: Uploading service .zip file to S3 (3.49 KB)...
    Serverless: Validating template...
    Serverless: Updating Stack...
    Serverless: Checking Stack update progress...
    ............
    Serverless: Stack update finished...
    Service Information
    service: sls-step-functions-example
    stage: dev
    region: us-east-1
    stack: sls-step-functions-example-dev
    api keys:
      None
    endpoints:
      None
    functions:
      hello: sls-step-functions-example-dev-hello
    Serverless StepFunctions OutPuts
    endpoints:
    

    シンプルなStep functions

    State Machineを追加したりする

    これだけでは普通のLambdaでええやんって話になるので、Step Functionsっぽいワークフローにしてみます。

    2つめのLambdaを追加する

    handler.jshello()と違うメッセージを返す関数を追加します。
    ワークフローの中で違うLambdaをよんだりするテストをするために使います。

    'use strict';
    
    module.exports.hello = (event, context, callback) => {
      const response = {
        statusCode: 200,
        body: JSON.stringify({
          message: 'Go Serverless v1.0! Your function executed successfully!',
          input: event,
        }),
      };
    
      callback(null, response);
    };
    
    module.exports.final = (event, context, callback) => {
      const response = {
        statusCode: 200,
        body: JSON.stringify({
          message: 'Passed final states',
          input: event,
        }),
      };
      callback(null, response);
    };
    

    serverless.ymlの更新

    追加した関数をLambdaにデプロイできるようにします。

    functions:
      hello:
        handler: handler.hello
      final:
        handler: handler.final
    

    stateMachineはこんな感じにしてみました。

    stepFunctions:
      stateMachines:
        hellostepfunc1:
          name: myStateMachine
          definition:
            Comment: "A Hello World example of the Amazon States Language using an AWS Lambda Function"
            StartAt: HelloWorld1
            States:
              HelloWorld1:
                Type: Task
                Resource: "arn:aws:lambda:us-east-1:99999:function:sls-step-functions-example-dev-hello"
                Next: waitUsingSeconds
                Retry:
                  - ErrorEquals:
                    - HandledError
                    IntervalSeconds: 1
                    MaxAttempts: 2
                    BackoffRate: 2
              waitUsingSeconds:
                Type: Wait
                Seconds: 10
                Next: Parallel
              Parallel:
                Type: Parallel
                Next: FinalState
                Branches:
                - StartAt: Wait 20s
                  States:
                    Wait 20s:
                      Type: Wait
                      Seconds: 20
                      End: true
                - StartAt: Pass
                  States:
                    Pass:
                      Type: Pass
                      Next: Wait 10s
                    Wait 10s:
                      Type: Wait
                      Seconds: 10
                      End: true
              FinalState:
                Type: Task
                Resource: "arn:aws:lambda:us-east-1:999999:function:sls-step-functions-example-dev-final"
                End: true
    

    これでデプロイすると、ちょっと複雑なワークフローに変わりました。

    実行すると、ちゃんとfinalのLambdaの戻り値が出力されていることがわかります。

    API Gatewayと連携させる

    stateMachinesのname / definitionと同じ階層にeventsを記述することで、Step Functionsを起動するイベントを指定できます。

    stepFunctions:
      stateMachines:
        hellostepfunc1:
          name: myStateMachine
          events:
            - http:
                path: hello
                method: GET
          definition:
            Comment: "A Hello World example of the Amazon States Language using an AWS Lambda Function"
    

    デプロイされたAPIをコールすると、Step Functionsの実行が始まったことがレスポンスで返ってきます。

    $ curl https://XXXXXXX.execute-api.us-east-1.amazonaws.com/dev/hello | jq .
      % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                     Dload  Upload   Total   Spent    Left  Speed
    100   147  100   147    0     0    175      0 --:--:-- --:--:-- --:--:--   175
    {
      "executionArn": "arn:aws:states:us-east-1:999999:execution:myStateMachine:de9e30fd-e989-11e7-b1e4-db09d1e378c9",
      "startDate": 1514216401.371
    }
    

    cronイベントなども設定可能ですので、ドキュメントをみていろいろトライしてみてください。

    そのほか

    Readmeにstate machineのサンプルがいろいろ紹介されてますので、そちらもぜひ触ってみてください。

    • ワークフローをMarkdownなどで書き出して整理
    • serverless.ymlでStateMachineにする
    • デプロイして使用する

    というワークフローが個人的にしっくりきそうですので、機会があれば導入してみたいなと思います。

    広告ここから
    広告ここまで
    Home
    Search
    Bookmark