본문 바로가기

DevOps

[AWS] AWS Step Function - Amazon States Language

AWS Step Functions:

  • AWS Step Functions는 서버리스 아키텍처를 구축하고 실행하기 위한 서비스로, 여러 AWS 서비스 간의 작업을 조정하고 관리하는데 사용됩니다. 
  • 이 서비스를 사용하면 비즈니스 로직을 정의하고 그 로직을 각 단계(Step)와 상태(State)로 분할하여 워크플로우를 쉽게 만들 수 있습니다. 
  • 각 상태(State)는 서로 다른 AWS 서비스의 작업(Task)을 나타내며, 이러한 상태들은 Step Functions에서 정의된 순서대로 실행됩니다. 
  • 예를 들어, 데이터 처리, Lambda 함수 실행, 또는 EC2 인스턴스 시작과 같은 다양한 작업을 조합하여 비즈니스 프로세스를 정의하고 관리할 수 있습니다. 

Amazon States Language:

  • Amazon States Language는 AWS Step Functions에서 사용하는 JSON 기반의 도메인 특화 언어 입니다. 
  • 이 언어를 사용하여 비즈니스 워크플로우를 선언적으로 정의하고 상태 전의, 병렬 처리, 조건부 논리 등을 표현할 수 있습니다. 
  • 각 상태는 일련의 특정 작업을 정의하며, 이러한 작업들은 입력 및 출력 데이터를 처리하거나 다음 상태로 이동하는데 사용됩니다. 
  • Amazon States Language는 워크플로우의 가독성을 높이고 관리를 용이하게 만들어 줍니다. 

아래는 아주 간단한 Amazon State Language 예제 입니다. 

{
  "Comment": "A simple minimal example of the States language",
  "StartAt": "Hello World", 
  "States": {
    "Hello World": {
      "Type" "Task",
      "Resource": "arn:aws:lambda:ap-northeast-2:123456789012:function:HelloWorld",
      "End": true
    }
  }
}
  • "Comment": 워크플로우에 대한 주석을 포함하고 있습니다. 주석은 워크플로우의 설명이나 문서화에 사용됩니다. 
  • "StateAt":워크플로우의 시작 지점을 지정합니다. 이 예제에서는 "Hello World"라는 상태로 시작합니다. 
  • "States": 워크플로우의 상태들을 정의하는 부분입니다. 
    • "Hello World": 상태의 이름으로, 이 상태는 "Type" 필드에서 "Task"로 정의됩니다. 이것은 Lambda함수와 같은 AWS 작업을 나타내는 Task 상태를 생성하는 것을 의미합니다. 
    • "Resource": Task 상태에서 수행할 작업을 정의합니다. "arn:aws:lambda:ap-northeast-2:123456789012:function:HelloWorld" 는 AWS Lambda 함수의 ARN(Amazon Resource Name)을 나타냅니다. 이 상태에서는 "HelloWorld" Lambda 함수가 실행됩니다. 
    • "End": "End" 필드가 'true'로 설정되어 있으므로, "Hello World" 상태가 실행된 후 워크플로우가 종료됩니다. 

이 예제는 "Hello World" Lambda 함수를 실행하고 종료하는 것이 전부인 간단한 예제입니다. 

 

조금 더 복잡한 예제로 상태를 어떻게 관리하고 어떻게 워크플로우를 구성하는지 살펴 보겠습니다. 

{
  "Comment": "Order Processing State Machine",
  "StartAt": "ReceiveOrder",
  "States": {
    "ReceiveOrder": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:us-east-1:123456789012:function:ReceiveOrderFunction",
      "Next": "ProcessOrder"
    },
    "ProcessOrder": {
      "Type": "Parallel",
      "Branches": [
        {
          "StartAt": "ValidateOrder",
          "States": {
            "ValidateOrder": {
              "Type": "Task",
              "Resource": "arn:aws:lambda:us-east-1:123456789012:function:ValidateOrderFunction",
              "Next": "PrepareOrder"
            },
            "PrepareOrder": {
              "Type": "Task",
              "Resource": "arn:aws:lambda:us-east-1:123456789012:function:PrepareOrderFunction",
              "End": true
            }
          }
        },
        {
          "StartAt": "ChargeCustomer",
          "States": {
            "ChargeCustomer": {
              "Type": "Task",
              "Resource": "arn:aws:lambda:us-east-1:123456789012:function:ChargeCustomerFunction",
              "End": true
            }
          }
        }
      ],
      "Next": "SendShippingNotification"
    },
    "SendShippingNotification": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:us-east-1:123456789012:function:SendShippingNotificationFunction",
      "End": true
    }
  }
}
  1.  "StartAt": 워크플로우의 시작을 나타내며 "ReceiveOrder"로 설정되어 있습니다. 이 State machine은 주문을 수신하는 작업 상태를 시작점으로 사용합니다. 
  2. "States": 상태 머신의 상태를 정의하는 섹션입니다. 이 예제에서는 다음과 같은 상태들이 있습니다. 
    • "ReceiveOrder": 주문을 수신하는 AWS Lambda 함수를 실행하는 'Task' 상태 입니다. 
      • "Next": 실행 후 전환될 상태를 정의합니다. 이 상태의 다음 상태는 "ProcessOrder" 입니다. 
    • "ProcessOrder": 이 상태는 병렬 처리를 통해 주문처리 작업을 분할하는 "Parallel" 상태입니다. 두개의 하위 상태 브랜치가 있으며, 각각 "ValidateOrder"와 "ChangeCustomer"로 시작됩니다. 두 하위 상태는 병렬로 실행됩니다. 
    • "ValidateOrder" 및 "PrepareOrder": 주문 유효성 검사 및 주문 준비를 위한 "Task" 상태입니다. "ValidateOrder"가 실행된 후에 "PrepareOrder"로 전환됩니다. 
    • "ChangeCustomer": 고객에게 결제를 처리하는 'Task' 상태입니다. 이것은 두 번째 병렬 처리 브랜치에서 실행됩니다. 
    • 두 개의 브랜치의 작업들이 실행된 후 "Next": SendShippingNotification" 정의에 의해 "SendShippingNotification" 상태로 전환됩니다. 
    • "SendShippingNotification": 배송 알림을 보내는 "Task" 상태입니다. "End": true 설정에 따라 이 작업이 실행된 후 워크플로우가 종요됩니다. 

 

 

반복 작업(Iterate) - "Map"

Amazon States Language에서 반복 작업(Iterate)을 설정하려면 "Map" 상태를 사용합니다. "Map" 상태는 입력 컬렉션의 각 요소에 대해 동일한 작업을 반복적으로 실행하고 결과를 모으는 데 사용됩니다. 이를 통해 데이터 변환, 병렬 처리 작업, 또는 여러 작업을 반복하는 등 다양한 시나리오를 처리할 수 있습니다. 

 

다음은 간단한 반복 작업 예제입니다. 이 예제는 주어진 숫자 목록을 제곱하는 작업을 반복합니다. 

{
  "Comment": "Simple example of iterating (mapping) over numbers",
  "StartAt": "IterateNumbers",
  "States": {
    "IterateNumbers": {
      "Type": "Map",
      "ItemsPath": "$.numbers",
      "MaxConcurrency": 2, // 동시에 실행할 작업의 최대 수 (옵션)
      "ResultPath": "$.squaredNumbers",
      "Iterator": {
        "StartAt": "Square",
        "States": {
          "Square": {
            "Type": "Task",
            "Resource": "arn:aws:lambda:ap-northeast-2:123456789012:function:SquaredFunction",
            "End": true
          }
        }
      },
      "End": true
    }
  }
}

이 예제에서 설명하는 주요 구성 요소는 다음과 같습니다. 

  1. "StartAt": 워크플로의 시작은 "IterateNumbers" 상태입니다. 
  2. "IterateNumbers": "Map" 상태로, "ItemsPath"에서 입력 데이터의 반복 대상 필드를 지정합니다. 이 예제에서는 "$.numbers" 필드를 반복합니다. 
    여기서 $는 JSON의 최상위 레벨을 나타냅니다. 
  3. "MaxConcurrency": (옵션) 동시에 실행할 작업의 최대 수를 설정합니다. 이 필드를 사용하면 동시에 실행되는 작업 수를 제한할 수 있습니다. 
  4. "ResultPath": 반복 작업의 결과를 저장할 경로를 정의합니다. 이 예제에서는 "$.squaredNumbers"에 제곱한 숫자를 저장합니다. 
  5. "Iterator": 반복 작업을 정의합니다. "StartAt"으로 "Square" 상태를 지정했고, "Square" 상태에서 주어진 숫자를 제곱하는 "Task" 상태를 실행합니다. 
  6. "End": "Map" 상태에 "End"를 true 로 설정하여 반복 작업이 완료된 후 워크플로우가 종료되도록 하였습니다. 

위 예제와 같이 Lambda 함수와 같은 작업을 "Resource" 필드에 설정하여 반복 작업을 수행하도록 할 수 있습니다. 

 

 

조건문 - "Choice"

Amazon States Languagge에서 조건문을 사용하여 조건에 따라 다른 작업을 설정하는 방법은 "Choice" 상태를 사용하는 것입니다. "Choice" 상태는 다양한 조건을 평가하고, 조건에 따라 서로 다른 다음 상태로 이동하도록 정의할 수 있습니다. switch/case 문과 유사한 기능을 제공합니다. 

 

{
  "StartAt": "CheckCondition",
  "States": {
    "CheckCondition": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.status",
          "StringEquals": "success",
          "Next": "SuccessState"
        },
        {
          "Variable": "$.status",
          "StringEquals": "failure",
          "Next": "FailureState"
        }
      ],
      "Default": "UnknownState"
    },
    "SuccessState": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:us-east-1:123456789012:function:SuccessFunction",
      "End": true
    },
    "FailureState": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:us-east-1:123456789012:function:FailureFunction",
      "End": true
    },
    "UnknownState": {
      "Type": "Fail",
      "Error": "UnknownError",
      "Cause": "Status is unknown"
    }
  }
}

 

이 예제에서 "CheckCondition" 상태는 $.status 변수의 값을 평가하고, 조건에 따라 다음 상태로 이동합니다. 여기에서 사용된 조건은 "Choices" 배열 안에 정의되며, 각 조건은 "Variable" (변수), "StringEquals" (문자열 동등 비교), 그리고 "Next"로 구성됩니다. 

  • 첫 번째 조건: "$.status"가 "success"와 동일한 경우 "SuccessState"로 이동합니다. 
  • 두 번째 조건: "$.status"가 "failure"와 동일한 경우 "FailureState"로 이동합니다. 
  • 기본(Default) 조건: 위 조건 중 어느 하나에도 해당하지 않는 경우 "UnknownState"로 이동합니다. 

이렇게 "Choice" 상태를 사용하면 다양한 조건을 평가하고 조건에 따라 상태 전이를 관리할 수 있습니다. 

 

다음은 선행 작업의 성공 여부에 따른 작업 선택 방법입니다. 

{
  "StartAt": "InvokeTask",
  "States": {
    "InvokeTask": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:us-east-1:123456789012:function:MyTaskFunction",
      "End": true,
      "Catch": [
        {
          "ErrorEquals": ["States.TaskFailed"],
          "Next": "HandleFailure"
        }
      ]
    },
    "HandleFailure": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:us-east-1:123456789012:function:HandleFailureFunction",
      "End": true
    }
  }
}

이 예제에서 "InvokeTask" 상태는 AWS Lambda 함수 "MyTaskFunction"을 실행하고, "Catch" 필드를 사용하여 실패한 경우 "HandleFailure" 상태로 이동합니다. 이렇게 하면 선행 작업의 성공 여부에 따라 다른 작업을 수행할 수 있습니다. 

 

변수의 값을비교하고, 조건을 설정할 때 사용할 수 있는 주요 필드와 연산자는 다음과 같습니다. 

  • "StringEquals": 문자열 값의 동등성을 비교하는 데 사용됩니다. 예를 들어, "StringEquals": "success"은 문자열이 "success"와 정확히 일치하는지 확인합니다.
  • "StringLessThan" 및 "StringGreaterThan": 문자열 값의 크기 비교를 위해 사용됩니다. 예를 들어, "StringLessThan": "b"는 문자열이 "b"보다 작은지 확인합니다.
  • "NumericEquals": 숫자 값의 동등성을 비교하는 데 사용됩니다. 예를 들어, "NumericEquals": 10은 숫자가 10과 정확히 일치하는지 확인합니다.
  • "NumericLessThan" 및 "NumericGreaterThan": 숫자 값의 크기 비교를 위해 사용됩니다. 예를 들어, "NumericLessThan": 5는 숫자가 5보다 작은지 확인합니다.
  • "BooleanEquals": 불리언 값의 동등성을 비교하는 데 사용됩니다. 예를 들어, "BooleanEquals": true는 값이 true와 정확히 일치하는지 확인합니다.
  • "TimestampEquals" 및 "TimestampGreaterThan": 타임스탬프 값을 비교하는 데 사용됩니다. 타임스탬프는 ISO 8601 형식을 따라야 합니다.
  • "ErrorEquals": 예외 또는 오류 유형을 비교하는 데 사용됩니다. "ErrorEquals" 필드를 사용하여 상태에서 발생한 예외 유형을 확인하고 처리할 수 있습니다. 예를 들어, "ErrorEquals": ["States.TaskFailed"]는 상태에서 발생한 TaskFailed 예외를 처리합니다.