Amazon web services AWS Step函数:如何访问在catch块中生成异常的状态输入?

Amazon web services AWS Step函数:如何访问在catch块中生成异常的状态输入?,amazon-web-services,error-handling,try-catch,aws-step-functions,state-machine-workflow,Amazon Web Services,Error Handling,Try Catch,Aws Step Functions,State Machine Workflow,我正在尝试使用状态机语言中定义的并行块和Catch块在我的step函数流中添加错误处理 以下是我的step功能流程图: 因为我希望所有步骤函数都有一个公共错误处理程序,所以我将它们包装在一个并行块中,并添加了一个公共Catch块来捕获任何步骤函数中的任何错误。通过查看各种示例和博客,我遵循了link并实现了类似的方法 我观察到的是,每当任何状态引发异常时,控件都会进入catch块。catch块的输入是引发的异常,该异常包含JSON对象中的错误和原因。由于我希望错误与传递到该状态的输入一起出现,

我正在尝试使用状态机语言中定义的并行块和Catch块在我的step函数流中添加错误处理

以下是我的step功能流程图:

因为我希望所有步骤函数都有一个公共错误处理程序,所以我将它们包装在一个并行块中,并添加了一个公共Catch块来捕获任何步骤函数中的任何错误。通过查看各种示例和博客,我遵循了link并实现了类似的方法

我观察到的是,每当任何状态引发异常时,控件都会进入catch块。catch块的输入是引发的异常,该异常包含JSON对象中的错误和原因。由于我希望错误与传递到该状态的输入一起出现,我在catch块中添加了ResultPath作为“$.error”。下面是定义状态机的JSON规范

    {
  "StartAt": "Try",
  "States": {
    "Try": {
      "Type": "Parallel",
      "Branches": [
        {
          "StartAt": "Step-1",
          "States": {
            "Step-1": {
              "Type": "Task",
              "Resource": "arn:aws:lambda:eu-west-1:1234:function:step-1-lambda",
              "Next": "Step-2"
            },
            "Step-2": {
              "Type": "Choice",
              "Choices": [
                {
                  "Variable": "$.some_variable",
                  "StringEquals": "some_string",
                  "Next": "Step-3"
                },
                {
                  "Variable": "$.some_variable",
                  "StringEquals": "some_other_string",
                  "Next": "Step-4"
                }
              ],
              "Default": "Step-6"
            },
            "Step-3": {
              "Type": "Task",
              "Resource": "arn:aws:lambda:eu-west-1:1234:function:step-3-lambda",
              "Next": "Step-6"
            },
            "Step-4": {
              "Type": "Task",
              "Resource": "arn:aws:lambda:eu-west-1:1234:function:step-4-lambda",
              "Next": "Step-6"
            },
            "Step-6": {
              "Type": "Task",
              "Resource": "arn:aws:lambda:eu-west-1:1234:function:step-6-lambda",
              "End": true
            }
          }
        }
      ],
      "Catch": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "ResultPath": "$.error",
          "Next": "ErrorHandler"
        }
      ],
      "Next": "UnwrapOutput"
    },
    "UnwrapOutput": {
      "Type": "Pass",
      "InputPath": "$[0]",
      "End": true
    },
    "ErrorHandler": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:eu-west-1:1234:function:step-7-lambda",
      "End": true
    }
  }
}

例如,考虑STEP4生成异常。此状态的输入为:

{
   "foo": "abc",
   "bar": "def"
}
触发状态机的输入为:

{
  "boo": "jkl",
   "baz": "mno"
}
在ErrorHandler中,当步骤4生成异常时,我希望ErrorHandler状态的输入为:

{
  "foo": "abc",
   "bar": "def",
   "error": {
       "Error": "SomeError",
       "Cause": "SomeCause"
   }
}
但是,接收的输入包含用于触发流的原始输入

{
  "boo": "jkl",
   "baz": "mno",
   "error": {
       "Error": "SomeError",
       "Cause": "SomeCause"
   }
}
我需要访问导致ErrorHandler中异常的状态的输入字段。它使用“$”提供用于触发流的输入。有什么办法可以做到这一点吗


任何帮助都将不胜感激,我一直在努力解决这个问题。

我只晚了10个月,没有那么多哈哈,但我希望你已经找到了解决办法,无论如何,我会分享我的两分钱,这样我可以帮助另一个开发人员,或者更好,有人可以告诉我更好的方法

首先,让我们看看我们有哪些场景:

  • Sych作业执行
  • 异步作业执行
我们的目标是:访问以某种方式触发错误的作业 第一个解决方案-适用于所有场景:
  • 基本上,将自定义的try-catch添加到所有作业资产中,换句话说,lambda函数应该抛出一个错误,提供有关正在使用它的作业的信息。我不太喜欢这种方法,因为为了在状态机中实现一些逻辑,您正在更改隔离的函数。最后,您将耦合两个独立的概念,您的状态机不需要外部工具来操作和记录其自身的上下文。我在这里可能错了,但那只是我的两分钱,请随意冒犯我的家人(只是开玩笑,但请随意纠正我)
第二个解决方案-应用于Sych作业执行
  • 在状态机中添加“addCatch”时,默认行为是覆盖步骤输入的错误输出。要解决这个问题,您只需要更改addCatch resultPath,这样您就可以将错误输出与步骤输入一起存储

    例:“捕获”:[ { “ErrorEquals”:[“States.All”], “下一步”:“ErrorHandler” “结果路径”:“$。错误信息” } ]

但为什么这很重要??????
  • 通过这种方式,您将能够访问errorHandlerJob中的步骤输入,这意味着您可以始终将步骤名称传递到下一个步骤输入,这样您将始终知道哪个作业失败。您不会通过直接更改lambda函数来实现这一点,而是通过使用作业的属性来解决耦合问题!但这在异步场景中不起作用,我将在下面解释
第三种解决方案——应用于异步作业执行
  • 前面的解决方案在这里不起作用,因为在这种情况下,您只能访问原始输入,因为您使用的是并行分支。所以我在这里所做的与上一个案例相似。我在并行分支中添加了Pass状态,这些Pass状态负责同步调用我的作业,而且我的所有作业都有自己的errorHandlingJob,没有不同的LAMBDA函数。我不会在AWS上创建新的资源,只有一个HandleError Lambda函数,所以我可以将监控重点放在该特定函数上。但是,我使用它为状态机必须执行的每个作业创建一个errorHandlingJob
  • 缺点是你的状态机现在有一个巨大的图形,但好的方面是你现在可以记录哪个作业失败了
如果没有任何抽象,它将是这样的“使用CDK” 但我还创建了一个抽象“ParallelStateMachineCatch”,因此您可以像这样使用: }

以下是ParallelStateMachineCatch代码:

import { Construct, Duration } from 'monocdk'
import { NodejsFunction } from 'monocdk/aws-lambda-nodejs'
import { Pass,Result, Parallel, ParallelProps } from 'monocdk/aws-stepfunctions'
import { LambdaInvoke } from 'monocdk/aws-stepfunctions-tasks'

export interface DefinitionProps {
  sonosEnvironment: string
  region: string
  accountNumber: string
}

export class ParallelStateMachineCatch extends Parallel {
  private errorHandler: NodejsFunction

  constructor(scope: Construct, id: string, props: ParallelProps, errorHandler: NodejsFunction) {
    super(scope, id, props)
    this.errorHandler = errorHandler
  }



  branchCatch(task: LambdaInvoke): ParallelStateMachineCatch {
    const randomId = Math.random().toString().replace('0.', '')
    const passInputJob = ParallelStateMachineCatch.generatePassInput(this, task.id, randomId)
    const handleErrorJob = ParallelStateMachineCatch.generateHandleErrorJob(this, this.errorHandler, randomId)
    const resultPath = '$.error-info'

    this.branch(passInputJob.next(task.addCatch(handleErrorJob, { resultPath })))

    return this
  }

  private static generateHandleErrorJob(scope: Construct, errorHandler: NodejsFunction, randomId: string): LambdaInvoke {
    return new LambdaInvoke(scope, `Handle Error ${ randomId }`, {
      lambdaFunction: errorHandler,
      outputPath: '$.Payload',
      timeout: Duration.seconds(5),
    })
  }

  private static generatePassInput(scope: Construct, stepName: string, randomId: string): Pass {
    return new Pass(scope, `Pass Input ${ randomId }`, {
      resultPath: '$.step-info',
      result: Result.fromObject({
        name: stepName
      })
    })
  }

}

无论如何,我希望我能在这方面帮助别人,这就是我解决这个问题的方法。请随意教我更好的方法!Tks
祝你好运,好代码

谢谢你提供图表和详细信息。我相信下面这样的东西可以帮助你:或者
this.definition = new ParallelStateMachineCatch(this, 
}, handleErrorFunction)
  .branchCatch(job1)
  .branchCatch(job2)
  .branchCatch(job3)
  .branchCatch(job4)
  .branchCatch(job5)
  .branchCatch(job6)
  .next(final)
import { Construct, Duration } from 'monocdk'
import { NodejsFunction } from 'monocdk/aws-lambda-nodejs'
import { Pass,Result, Parallel, ParallelProps } from 'monocdk/aws-stepfunctions'
import { LambdaInvoke } from 'monocdk/aws-stepfunctions-tasks'

export interface DefinitionProps {
  sonosEnvironment: string
  region: string
  accountNumber: string
}

export class ParallelStateMachineCatch extends Parallel {
  private errorHandler: NodejsFunction

  constructor(scope: Construct, id: string, props: ParallelProps, errorHandler: NodejsFunction) {
    super(scope, id, props)
    this.errorHandler = errorHandler
  }



  branchCatch(task: LambdaInvoke): ParallelStateMachineCatch {
    const randomId = Math.random().toString().replace('0.', '')
    const passInputJob = ParallelStateMachineCatch.generatePassInput(this, task.id, randomId)
    const handleErrorJob = ParallelStateMachineCatch.generateHandleErrorJob(this, this.errorHandler, randomId)
    const resultPath = '$.error-info'

    this.branch(passInputJob.next(task.addCatch(handleErrorJob, { resultPath })))

    return this
  }

  private static generateHandleErrorJob(scope: Construct, errorHandler: NodejsFunction, randomId: string): LambdaInvoke {
    return new LambdaInvoke(scope, `Handle Error ${ randomId }`, {
      lambdaFunction: errorHandler,
      outputPath: '$.Payload',
      timeout: Duration.seconds(5),
    })
  }

  private static generatePassInput(scope: Construct, stepName: string, randomId: string): Pass {
    return new Pass(scope, `Pass Input ${ randomId }`, {
      resultPath: '$.step-info',
      result: Result.fromObject({
        name: stepName
      })
    })
  }

}