AWS SAM,如何通过api网关调用运行状态机?

时间:2020-02-28 21:08:19

标签: amazon-web-services serverless aws-sam aws-sam-cli

我正在尝试为工作流设置状态机,但是对于我一生来说,我似乎无法使其正常工作,这是我的SAM模板:

AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: >
  strest

  Sample SAM Template for strest

Globals:
  Function:
    Timeout: 3

Resources:
  PublicApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: Prod
      # TracingEnabled: true
      DefinitionBody:
        swagger: "2.0"
        info:
          version: "1.1"
          title: "StrestApi"
        schemes:
          - "http"
        paths:
          /start: # api gateway invokes lambda synchronously, which in turn invokes the stepfunction and waits for its final result
            get:
              produces:
                - "application/json"
              responses:
                "200":
                  description: "200 response"
                  schema:
                    $ref: "#/definitions/Empty"
                  headers:
                    Access-Control-Allow-Headers:
                    type: "string"

              security: []
              x-amazon-apigateway-integration:
                responses:
                  default:
                    statusCode: "200"
                    headers:
                      Access-Control-Allow-Headers:
                      type: "'*'"
                httpMethod: GET
                type: aws_proxy
                uri:
                  Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${StartFunction.Arn}/invocations

        definitions:
          Empty:
            type: "object"
            title: "Empty Schema"

  # Role which allows step functions to invoke lambda functions
  StatesExecutionRole:
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal:
              Service:
                - !Sub states.${AWS::Region}.amazonaws.com
            Action: "sts:AssumeRole"
      Path: "/"
      Policies:
        - PolicyName: StatesExecutionPolicy
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - "lambda:InvokeFunction"
                Resource: "*"

  # LAMBDAS
  StartFunction:
    Type: AWS::Serverless::Function
    Properties:
      Description: Starts the state machine
      CodeUri: dist/
      Handler: start/start.handler
      Runtime: nodejs12.x
      Environment:
        Variables:
          STEP_FUNCTION_ARN: !Ref StepFunctionsStateMachine
      Policies:
        - Version: "2012-10-17"
          Statement:
            - Effect: "Allow" # step function permissions open for now
              Action:
                - states:*
              Resource: "*"
      Events:
        ExecSFNResource:
          Type: Api
          Properties:
            RestApiId: !Ref PublicApi
            Path: /start
            Method: GET

  ExecutorFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: dist/
      Handler: executor/executor.handler
      Runtime: nodejs12.x
      # Events:
      #   HelloWorld:
      #     Type: Api
      #     Properties:
      #       Path: /execute
      #       Method: get

  # State machine
  StepFunctionsStateMachine:
    Type: AWS::StepFunctions::StateMachine
    Properties:
      RoleArn: !GetAtt [StatesExecutionRole, Arn]
      DefinitionString: !Sub |-
        {
          "StartAt": "execute",
          "Comment": "State machine for executing the strest main loop",
          "States": {
            "execute": {
              "Type": "Task",
              "Resource": "${ExecutorFunction.Arn}",
              "Comment": "Run the Executor Lambda function",
              "End": true
            }
          }
        }

我可以通过执行sam local start-apisam local start-lambda来启动服务。

  1. 使用以下两个命令之一启动api有什么区别?
  2. 在我粘贴的模板中,我正在使用!Ref获取状态机ARN,但是此方法不起作用,返回了相同的字符串,如果我将其更改为!GetAtt StepFunctionsStateMachine.Arn,则可以正常工作< / li>
  3. 更改2后,然后查询/start端点,开始运行lambda函数,我得到了状态机的信息,但是当我尝试启动它时,却出现了Service not valid in this context: lambda错误(在标记2之后),以下是启动函数的代码:
import AWS from "aws-sdk";

export async function handler(event: any, context: any) {
  let stepFunctionArn = process.env.STEP_FUNCTION_ARN;

  console.log("marker0 stepFunctionArn", stepFunctionArn);

  let params = {
    stateMachineArn: stepFunctionArn!,
    name: "Execution lambda " + new Date().toString()
  };
  console.log("marker 1");

  let sf_client = new AWS.StepFunctions();
  console.log("marker 2");

  let res = await sf_client.startExecution(params).promise();

  console.log("marker 3", res);

  return {};
}

1 个答案:

答案 0 :(得分:1)

从Lambda函数启动步进函数是可行的,但是我认为在您的情况下,使用API​​ Gateway的DefinitionBody直接从Api Gateway启动它是一个更好的解决方案:

  /workflow:
    post:
      x-amazon-apigateway-integration:
        credentials:
          Fn::GetAtt: [ ApiGatewayStepFunctionsRole, Arn ]
        uri:
          Fn::Sub: arn:aws:apigateway:${AWS::Region}:states:action/StartExecution
        httpMethod: POST
        type: aws
        responses:
          default:
            statusCode: 200
            responseTemplates:
              application/json: |
                '{ "executionId": "$input.json('executionArn').split(':').get(7) }'
        requestTemplates:
          application/json:
            Fn::Sub: |-
              {
                "input": "$util.escapeJavaScript($input.json('$'))",
                "name": "$context.requestId",
                "stateMachineArn": "${Workflow}"
              }
      summary: Start workflow instance
      responses:
        200:
          $ref: '#/components/responses/200Execution'
        403:
          $ref: '#/components/responses/Error'

我在https://github.com/jvillane/aws-sam-step-functions-lambda/blob/master/openapi.yaml的github中提交了一个有效的示例,其中带有检查执行状态的其他方法。