티스토리 뷰

이 글은 Create a Serverless Workflow 튜토리얼 글을 따라 하면서 내용을 최신으로 바꾸고 적당히 순서도 바꿔가며 작성한 글이다.

Lambda에서 Lambda를 호출하려면 어떻게 해야할까? 여러가지 방법이 있겠지만 flow에 따라 적절한 Lambda 함수가 호출되도록 하기에 가장 적절한 솔루션은 AWS Step Functions 라고 생각한다.

State Machine & Serverless Workflow 생성

우리가 만들 Workflow는 아래를 수행한다.

  1. Support Case를 생성하는 Lambda Function을 호출
  2. 문제 해결 담당자에게 Assign 하는 Lambda Function을 Invoke
  3. ...

이 과정에서 Lambda Function들 간에 Data를 전달하여 Support Case의 상태를 추적하도록 한다.

위의 워크플로우는 아래와 같다.

Lambda 생성

우선 AWS Step Functions의 Workflow를 만들기 전에 안에서 사용 되는 Lambda를 먼저 만들자. 모두 기본 Lambda 권한을 가진 새 역할 생성 옵션을 통해 Role을 새로 만들고, Runtime으로는 Node 12.x를 갖는다.

OpenCaseFunction

exports.handler = async (event) => {
    // Support Case를 만든다. 
    // Input으로 inputCaseID를 받는다 
    // Return 으로 확인 메세지를 반환 한다
    var myCaseID = event.inputCaseID;
    var myMessage = "Case " + myCaseID + ": opened...";   
    var result = {Case: myCaseID, Message: myMessage};
    return result;
};

단순히 inputCaseID를 받아서 확인 메세지를 리턴한다.

AssignCaseFunction

exports.handler = async (event) => {
    // Case와 Message를 받아서 Assigned 메세지를 리턴한다.
    var myCaseID = event.Case;    
    var myMessage = event.Message + "assigned...";    
    var result = {Case: myCaseID, Message: myMessage};
    return result;
};

WorkOnCaseFunction

exports.handler = async (event) => {
    // 랜덤 숫자를 생성해서 Support Case가 해결 됐는지 결정한다
    // 그 후 메세지와 함께 해결 여부를 리턴 한다.
    var min = 0;
    var max = 1;    
    var myCaseStatus = Math.floor(Math.random() * (max - min + 1)) + min;
    var myCaseID = event.Case;
    var myMessage = event.Message;
    if (myCaseStatus == 1) {
        // Support case has been resolved    
        myMessage = myMessage + "resolved...";
    } else if (myCaseStatus == 0) {
        // Support case is still open
        myMessage = myMessage + "unresolved...";
    } 
    var result = {Case: myCaseID, Status : myCaseStatus, Message: myMessage};
    return result;
};

CloseCaseFunction

exports.handler = async (event) => {
    // Support Ticket을 Close 한다. (앞에 있는 Lambda에서 Resolve 한거겠지?)
    var myCaseStatus = event.Status;    
    var myCaseID = event.Case;    
    var myMessage = event.Message + "closed.";    
    var result = {Case: myCaseID, Status : myCaseStatus, Message: myMessage};
    return result;
};

EscalateCaseFunction

exports.handler = async (event) => {
    // Support Case를 Escalate한다. 
    var myCaseID = event.Case;    
    var myCaseStatus = event.Status;    
    var myMessage = event.Message + "escalating.";    
    var result = {Case: myCaseID, Status : myCaseStatus, Message: myMessage};
    return result;
};

결국 위 Lambda Function들이 하는 일은 그냥 Input을 받고, Return을 하는 일이 전부다.

그러면 어디로 부터 Input을 받고, Return값은 어디로 가는가? 그 Flow를 컨트롤 하는게 Step Functions가 하는 일이다.

State 생성

AWS Step Functions 에 들어가서 아래의 Amazon States Languages를 정의 한다

{
  "Comment": "A simple AWS Step Functions state machine that automates a call center support session.",
  "StartAt": "Open Case",
  "States": {
    "Open Case": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:REGION:ACCOUNT_ID:function:OpenCaseFunction",
      "Next": "Assign Case"
    },
    "Assign Case": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:REGION:ACCOUNT_ID:function:AssignCaseFunction",
      "Next": "Work on Case"
    },
    "Work on Case": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:REGION:ACCOUNT_ID:function:WorkOnCaseFunction",
      "Next": "Is Case Resolved"
    },
    "Is Case Resolved": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.Status",
          "NumericEquals": 1,
          "Next": "Close Case"
        },
        {
          "Variable": "$.Status",
          "NumericEquals": 0,
          "Next": "Escalate Case"
        }
      ]
    },
    "Close Case": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:REGION:ACCOUNT_ID:function:CloseCaseFunction",
      "End": true
    },
    "Escalate Case": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:REGION:ACCOUNT_ID:function:EscalateCaseFunction",
      "Next": "Fail"
    },
    "Fail": {
      "Type": "Fail",
      "Cause": "Engage Tier 2 Support."
    }
  }
}

이 때 REGION와 ACCOUNT_ID는 각자한테 적절한 값으로 입력한다.

그리고 Refresh 버튼을 누르면 아래와 같이 Workflow Visual 이 생성된다.

이제 다음 버튼을 눌러 IAM Role을 생성하자

상태 머신 이름은 SupportTicketFlow로 하였다.

역할은 새 역할 생성으로 해놓고 상태 머신 생성 버튼을 누르자

자동으로 Lambda Invoke PolicyXRay Access Policy를 갖는 Step Functions Service Role을 생성할 것이다.(참고로 Step Functions의 Service명?은 states.amazon.com 이다)

실행

이제 실행 시작 버튼을 눌러서 Step Functions의 State Machine을 실행해 보자

입력 사항에는 아래의 JSON을 입력 한다

{
    "inputCaseID": "Case1"
}

기타 사항

만약 State 생성 코드에서 람다를 호출 할 때 버전을 같이 써주는 경우 아래와 같은 에러가 나면서 실행이 안된다.

예를 들면 아래 처럼 State 코드를 작성 하는 경우

"Open Case": {
  "Type": "Task",
  "Resource": "arn:aws:lambda:REGION:ACCOUNT_ID:function:OpenCaseFunction:$LATEST",
  "Next": "Assign Case"
}

실행 시 아래와 같은 에러가 난다.

User: arn:aws:sts::070362291234:assumed-role/StepFunctions-SupportTicketFlow-role-430cb512/ZozRcmbisjheXWbBaXFnKtrnutSQnhmP is not authorized to perform: lambda:InvokeFunction on resource: arn:aws:lambda:us-west-2:070362291234:function:OpenCaseFunction:$LATEST (Service: AWSLambda; Status Code: 403; Error Code: AccessDeniedException; Request ID: e63e4b6d-eaaf-4754-97af-bfee2a7a6e06)

IAM 들어가서 확인 해보면, Lambda를 Invoke하는 Policy의 Resource가 Lambda Function의 Version은 명시를 안해놨다. 따라서 Version을 추가 하고 싶다면, IAM에 들어가서 직접 편집을 통해 버전을 적거나 함수 이름 끝에 :* 를 적어야 한다.

Flow 사이에 주고 받는 변수들 확인

람다의 Input 및 result를 모두 로그로 확인 하고 싶다면 State Machine 생성시 하단에 있는 로깅에서 로그 수준을 ALL로 설정하면 CloudWatch를 통해 확인 가능하다

결론

Lambda를 통하여 진행 되는 Workflow의 경우 AWS Step Functions는 최고의 솔루션이다.

Flow의 조건을 Lambda에 적을 필요 없이 Step Functions의 State Machine을 통해 작성 할 수 있기 때문에 관리가 깔끔해 진다.

Lambda 뿐만 아니라 EMR Cluster 생성, 종료, DDB 항목 CURL, Glue Job, SNS Publish 등 다양한 Task를 State Machine에서 Call 하는게 가능하다.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함