通过 aws Step Functions 中的失败状态传播错误消息

Propogating error message through Fail state in aws Step Functions

我正在使用 aws Step Functions 来管理工作流程。我正在使用失败状态来处理工作流中的错误。我想传播 Step Function 工作流程中的一些 json,以便用户可以轻松识别错误来源。因此,例如,如果 json 输入失败状态如下所示:

{
    "error": "some error text",
    "other_stuff": {...}
}

那我想拉一下错误的来源。我已经像这样设置了我的失败状态:

FailState:
    Type: Fail
    Cause: States.Format($.error)
    Error: Failure Here

但是,这只会生成文字字符串 States.Format($.error) 作为失败状态的原因。如何使用 aws 状态语言和失败状态将实际错误显示为失败状态输出的一部分?任何可以成功地将错误文本从步骤输入传播到失败状态的步骤输出的解决方案都足以解决这个问题。

如果其他人遇到这个问题,我联系了 AWS 支持,他们告诉我的是这样的:

“此状态下的‘原因’和‘错误’字段仅接受字符串类型值。这就是为什么您将文字字符串作为响应。但是,好消息是,我们已经有了一个现有功能请求,待 Step Functions 开发团队处理,以实现将 JSON 路径(如 $.error)发送到失败状态的功能。“

所以出于某种原因,AWS 步骤函数不允许您传递动态错误消息。他们确实提供了一些解决方法,例如将失败状态更改为成功并以这种方式传播错误消息,或者在状态机失败的情况下创建一个 sns 主题 post 到。我个人刚刚更新了状态轮询 API 以获取索引 [-2] 处的状态以将错误传播给用户。无论如何,要使用此功能,目前应该采用一些解决方法,希望 AWS 能够尽快推出此功能。

我也想在失败状态下使用 JSON 路径来动态设置 CauseError 字段。在我的例子中,我有一组已知的错误,所以我为每个错误创建了一个单独的失败状态。这些失败状态中的每一个都对应一个捕获对象,其中 Next 被设置为适当的失败状态。

{
  "TaskState": {
    "Type": "Task",
    ...
    "Catch": [
      {
         "ErrorEquals": ["ErrorA"],
         "Next": "FailureA"
      },
      {
         "ErrorEquals": ["ErrorB"],
         "Next": "FailureB"
      }
    ]
  },
  "FailureA": {
    "Type": "Fail",
    "Error": "FailureA",
    "Cause": "This failed because of A"
  },
  "FailureB": {
    "Type": "Fail",
    "Error": "FailureB",
    "Cause": "This failed because of B"
  }
}

我能够通过创建一个因未处理的异常而失败的“Fail-Me”Lambda 实现接近期望的行为,根据作为其负载提供的错误和原因动态选择异常 class .如果“Error”是内置异常的名称 class,它会使用它,否则它会创建自己的 class.

在状态机中,使用 Invoke Lambda 状态调用此“Fail-Me”lambda,没有重试器和捕捉器。

import inspect, sys

# Expected payload (event), example:
#      {
#           "Error":"RuntimeError",
#           "Cause":"No Cause"
#       }

def lambda_handler(event, context):
    
    ErrorType  = event.get("Error") or ""
    ErrorCause = event.get("Cause") or ""


    if not ErrorType.isidentifier():
        ErrorCause = "{}: {}".format(ErrorType, ErrorCause)
        ErrorType = "OtherError"

    DynamicExceptionClass = type(ErrorType, (BaseException,), {})

    for name, obj in inspect.getmembers(sys.modules["builtins"]):
        if inspect.isclass(obj) and issubclass (obj, BaseException):
            if name==ErrorType:              #ErrorType is an existing built-in exception - use it
                raise obj(ErrorCause)


    #Create our own dynamic class and raise it

    DynamicExceptionClass = type(ErrorType, (BaseException,), {})

    raise DynamicExceptionClass(ErrorCause)