Step Functions의 Error Handing를 해봤습니다.

2022.02.28

안녕하세요, 임채정입니다.
이번 블로그에서는 Step Functions의 Error Handing에 대해 알아보고 테스트해보겠습니다.
Step Functions이 뭔지 알고 싶으신 분은 아래 블로그를 참고하세요.

아젠다

  1. Error Handing 이란
  2. 실제로 해보기
  3. 마무리

1. Error Handing 이란

  • 오류를 처리하는 기능
  • 오류의 여러가지 발생 원인
    • 스테이트 머신의 정의 문제
      • Choice 상태에 일치하는 룰이 없는 경우
    • 작업 실패
      • Lambda 함수의 예외
    • 일시적인 문제
      • 네트워크 파티션 이벤트
  • 기본적으로는 상태에서 오류가 보고되면 AWS Step Functions 실행 전체가 실패

오류의 종류

  • States.ALL
    • 정의되어진 오류 이름과 일치하는 모든 오류에 해당하는 경우
  • States.DataLimitExceeded
    • 커넥터의 출력이 페이로드 크기 할당량보다 큰 경우
    • 상태 출력이 페이로드 크기 할당량보다 큰 경우
    • Parameters 처리 후 상태 입력이 페이로드 크기 할당량보다 큰 경우
  • States.Runtime
    • 처리할 수 없는 일부 예외로 인해 실행이 실패한 경우
  • States.HeartbeatTimeout
    • HeartbeatSeconds 값보다 장시간 실행되어 하트비트 전송에 실패한 경우
  • States.Timeout
    • TimeoutSeconds 값보다 장시간 실행되었거나 HeartbeatSeconds 값보다 긴 간격 하트 비트 송신에 실패 경우
  • States.TaskFailed
    • 실행 중 실패한 경우
    • States.Timeout 이외의 모든 기존의 에러명에 일치하는 경우에도 사용 가능
  • States.Permissions
    • 지정된 코드를 실행하기에 충분한 권한이 없는 경우
  • 커스텀 오류
    • 사용자가 만드는 오류

2. 실제로 해보기

이번에는 실제로 Error Handing을 어떤 식으로 하면 되는지 해보도록 하겠습니다.

먼저 이번에 해볼 워크플로입니다.

그럼 실제로 람다 함수와 Step Functions의 상태 머신을 작성해보겠습니다.

람다 함수

먼저 InvokeFunction 단계에 들어갈 에러를 발생시킬 람다 함수를 작성하겠습니다.
함수 생성에서 블루프린트 사용을 선택하고 step-functions 을 검색해서 step-functions-error 을 선택하고 구성을 눌러줍니다.

구성에서는 이름 등을 입력할 수 있습니다.
또한, Step Functions 의 커스텀 error 에 대한 출력을 하는 기본적인 코드가 작성되어 있는데 이 코드는 수정하지 않은 채로 함수를 생성해주겠습니다.

함수가 생성되면 위에서 확인했던 코드 소스를 볼 수 있습니다.

테스트를 해보면 에러 결과가 제대로 출력되는 것을 확인할 수 있습니다.

Test Event Name
FunctionTest

Response
{
  "errorType": "CustomError",
  "errorMessage": "This is a custom error!",
  "trace": [
    "Error",
    "    at Runtime.exports.handler (/var/task/index.js:6:29)",
    "    at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)"
  ]
}

Function Logs
START RequestId: 0cfdb0ac-a5d7-4030-bc3b-44b5afc5e0d0 Version: $LATEST
2022-02-24T06:03:46.155Z	0cfdb0ac-a5d7-4030-bc3b-44b5afc5e0d0	ERROR	Invoke Error 	{"errorType":"CustomError","errorMessage":"This is a custom error!","name":"CustomError","message":"This is a custom error!","stack":["Error","    at Runtime.exports.handler (/var/task/index.js:6:29)","    at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)"]}
END RequestId: 0cfdb0ac-a5d7-4030-bc3b-44b5afc5e0d0
REPORT RequestId: 0cfdb0ac-a5d7-4030-bc3b-44b5afc5e0d0	Duration: 29.65 ms	Billed Duration: 30 ms	Memory Size: 128 MB	Max Memory Used: 55 MB	Init Duration: 161.39 ms

Request ID
0cfdb0ac-a5d7-4030-bc3b-44b5afc5e0d0

이것으로 커스텀 에러를 발생시키는 함수 작성이 끝났습니다.

상태 머신 작성

이번에는 Step Functions 의 상태 머신을 작성해보겠습니다.
코드로 워크플로 작성을 선택해주고 표준을 선택해줍니다.

정의 부분에서 아래 코드를 붙여 줍니다.
아래 코드에서는 Retry 필드에서 ErrorEquals 의 값과 같은 오류가 발생할 경우 설정한 값은 다음과 같습니다.

  • IntervalSeconds 필드에서 첫 번째 재시도 전에 기다리는 시간 (초) 설정
  • MaxAttempts 필드로 최대 재시도 횟수 설정
  • BackoffRate 필드로 재시도 때마다 재시도 간격이 늘어나도록 곱하는 수를 설정했습니다.

또한, Catch 필드에서 오류를 처리하고 있습니다.

즉, CustomError 가 발생할 경우 2번을 재시도 하고 첫 번째 재시도 전에 1초를 기다리고 그 후에는 2배를 곱한 수로 재시도를 실행한다는 뜻입니다.

{
    "Comment": "A Retry and Catch example",
    "StartAt": "InvokeFunction",
    "States": {
      "InvokeFunction": {
        "Type": "Task",
        "Resource": "arn:aws:lambda:REGION:ACCOUNT_ID:function:FUNCTION_NAME",
        "Retry": [
          {
            "ErrorEquals": [
              "CustomError"
            ],
            "IntervalSeconds": 1,
            "MaxAttempts": 2,
            "BackoffRate": 2
          },
          {
            "ErrorEquals": [
              "States.TaskFailed"
            ],
            "IntervalSeconds": 10,
            "MaxAttempts": 2,
            "BackoffRate": 2
          },
          {
            "ErrorEquals": [
              "States.ALL"
            ],
            "IntervalSeconds": 5,
            "MaxAttempts": 5,
            "BackoffRate": 2
          }
        ],
        "Catch": [
          {
            "ErrorEquals": [
              "CustomError"
            ],
            "Next": "CustomErrorFallback"
          },
          {
            "ErrorEquals": [
              "States.TaskFailed"
            ],
            "Next": "TaskFailedFallback"
          },
          {
            "ErrorEquals": [
              "States.ALL"
            ],
            "Next": "AllErrorFallback"
          }
        ],
        "End": true
      },
      "CustomErrorFallback": {
        "Type": "Pass",
        "Result": "custom lambda function exception",
        "End": true
      },
      "TaskFailedFallback": {
        "Type": "Pass",
        "Result": "TaskFailed error code",
        "End": true
      },
      "AllErrorFallback": {
        "Type": "Pass",
        "Result": "ALL error code",
        "End": true
      }
    }
  }

Resource 에는 아까 위에서 작성한 람다 함수의 ARN을 붙여 줍니다.

그러면 코드에 따른 워크플로를 시각적으로도 확인할 수 있습니다.

이걸로 상태 머신의 작성이 끝났습니다.

결과 테스트

그럼 작성한 상태 머신을 실제로 실행시켜서 동작을 확인해보겠습니다.
별다른 설정없이 실행을 시작합니다.

다음과 같은 결과가 나왔습니다.

실행 이벤트 내역을 통해 좀 더 자세히 살펴보겠습니다.

1) InvokeFunction 단계에서 실행된 람다 함수는 CustomError 가 발생하는 함수이기 때문에 CustomError 가 발생했습니다.

2) 람다 함수는 총 3번의 실행을 했습니다. (2번은 재실행: "MaxAttempts": 2)

3) 재시도 후에도 CustomError 가 발생했기 때문에 output으로 CustomError 를 출력했습니다.

4) 그 후 CustomErrorFallback 단계에서 End 에 도달

그럼 이번에는 CustomError 가 아니라 TaskFailed 에러를 발생시켜보겠습니다.
람다 함수를 수정해서 input 으로 들어가는 에러의 이름을 다른 것으로 수정합니다.

그 후 실행을 시작합니다.

이번 실행 결과입니다. 이번에는 TaskFailedFallback 단계를 통해 End 에 도달했습니다.

실행 이벤트 내역을 통해 살펴보면

1) InvokeFunction 단계에서 실행된 람다 함수에서 OtherError 에러 발생

2) 람다 함수는 총 3번의 실행을 했습니다. (2번은 재실행: "MaxAttempts": 2)

3) 재시도 후에도 OtherError 에러가 계속 발생했기 때문에 output으로 OtherError 를 출력했습니다.

4) TaskFailed 에러는 States.Timeout 이외의 모든 에러명이 일치하는 에러명이 없을 때 발생하기 때문에 TaskFailedFallback 단계로 넘어가서 End 에 도달

3. 마무리

이번 블로그에서는 Step Functions 서비스의 상태 머신에서 에러 처리를 하는 법에 대해서 알아보고 정리해봤습니다.
RetryCatch 의 다양한 필드를 통해 커스텀 에러와 정의되어진 기존 에러의 처리방법을 정의할 수 있어서 좋은 기능이라고 생각합니다.