Step Functions 中的错误处理 - Amazon Step Functions
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 Amazon Web Services 服务入门

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

Step Functions 中的错误处理

任何状态都可能会遇到运行时错误。错误的发生可能有多种原因,例如以下示例:

  • 状态机定义问题(例如,Choice 状态中没有匹配规则)

  • 任务失败(例如,Amazon Lambda 函数中的异常)

  • 临时性问题(例如,网络分区事件)

默认情况下,当某个状态报告错误时,Amazon Step Functions 会导致执行完全失败。

要向您部署错误处理示例,请参阅 ThAmazon Web Services 账户 e Workshop 的模块 8-错误Amazon Step Functions处理

错误名称

Step Functions 使用区分大小写的字符串(称为错误名称)识别亚马逊状态语言中的错误。Amazon States 语言定义了一组命名众所周知错误的内置字符串,所有字符串都以States.前缀开头。

States.ALL

一个与任何已知错误名称匹配的通配符。

注意

此错误类型无法catchStates.DataLimitExceeded 终端错误类型和运行时错误类型。有关这些错误类型的更多信息,请参阅States.DataLimitExceededStates.Runtime

States.BranchFailed

一个Parallel州的分支失败了。

States.DataLimitExceeded

在以下条件下,Step Functions 报告States.DataLimitExceeded异常:

  • 当连接器的输出大于有效负载大小配额时。

  • 当状态的输出大于负载大小配额时。

  • Parameters处理后,当状态的输入大于负载大小配额时。

有关配额的更多信息,请参阅配额

注意

这是错误类型无法捕获的终端States.ALL错误。

States.ExceedToleratedFailureThreshold

Map状态失败是因为失败项的数量超过了状态机定义中指定的阈值。有关更多信息,请参阅Map 状态的容许故障阈值

States.HeartbeatTimeout

Task状态未能发送心跳的时间超过该HeartbeatSeconds值。

注意

此错误仅在CatchRetry字段中可用。

States.IntrinsicFailure

尝试在有效载荷模板中调用内部函数失败。

States.ItemReaderFailed

Map状态失败,因为它无法从ItemReader字段中指定的项目源读取。有关更多信息,请参阅ItemReader

States.NoChoiceMatched

Choice状态未能将输入与选择规则中定义的条件相匹配,并且未指定默认转换。

States.ParameterPathFailure

尝试在状态字段中替换名称以路径结尾的Parameters.$字段失败。

States.Permissions

Task状态失败,因为它没有足够的权限运行指定的代码。

States.ResultPathMatchFailure

Step Functions 未能将状态ResultPath字段应用于接收到的状态的输入。

States.ResultWriterFailed

Map状态失败,因为它无法将结果写入ResultWriter字段中指定的目的地。有关更多信息,请参阅ResultWriter

States.Runtime

由于无法处理某些异常,执行失败。这些通常是由运行时的错误引起的,例如尝试在 null JSON 有效负载上应用 InputPathOutputPathStates.Runtime错误是不可检索的,并且总是会导致执行失败。重试或重试States.ALL不会catchStates.Runtime 错误。

States.TaskFailed

一个在执行期间失败的 Task 状态。在重试或catch 中使用时,States.TaskFailed充当通配符,可匹配除以下以外的任何已知错误名称States.Timeout

States.Timeout

一个 Task 状态,该状态要么运行时间长度超过 TimeoutSeconds 值,要么在超过 HeartbeatSeconds 值的时段长度中未能发送检测信号。

状态可以报告具有其他名称的错误。但是,这些错误名称不能以States.前缀开头。

作为最佳实践,确保生产代码可以处理 Amazon Lambda 服务异常(Lambda.ServiceExceptionLambda.SdkClientException)。有关更多信息,请参阅处理 Lambda 服务异常

注意

Lambda 中未处理的错误如错误输出Lambda.Unknown中所报告。其中包括 out-of-memory 错误和函数超时。您可以在Lambda.UnknownStates.ALL、或上进行匹配States.TaskFailed来处理这些错误。当 Lambda 达到最大调用次数时,错误为Lambda.TooManyRequestsException。有关 Lambda 函数错误的更多信息,请参阅Amazon Lambda开发者指南中的错误处理和自动重试

出错后重试

TaskParallel 状态可以有名为 Retry 的字段,其值必须是称为重试器 的对象的数组。一个重试器表示特定重试次数,通常重试之间的时间间隔会增加。

注意

重试被视为状态转换。有关状态转换如何影响计费的信息,请参阅 Step Functions 定价

重试器包含以下字段:

ErrorEquals (必需)

一个匹配错误名称的非空字符串数组。当某个状态报告错误时,Step Functions 会扫描检索器。当错误名称出现在此数组中时,它实施该重试器描述的重试策略。

IntervalSeconds(可选)

一个整数,表示第一次重试前的秒数(1默认情况下)。 IntervalSeconds的最大值为99999999

MaxAttempts(可选)

一个正整数,表示重试的最大次数 (默认值为 3)。如果错误重复发生超过指定次数,则停止重试并恢复正常错误处理。值为0指定从不重试错误。 MaxAttempts的最大值为99999999

BackoffRate(可选)

每次重试尝试后,所表示的重试间隔IntervalSeconds增加的乘数。默认情况下,该BackoffRate值会增加2.0

以下示例 a 进行了Retry两次重试,第一次重试在等待三秒钟后发生,第二次重试是在第一次重试后等待三秒钟后进行的。要查看完整示例,请参阅上的stepfunction-error-handling-examples存储库 GitHub。

"Retry": [ { "ErrorEquals": [ "States.Timeout" ], "IntervalSeconds": 3, "MaxAttempts": 2, "BackoffRate": 1 } ]

重试器的 ErrorEquals 字段中显示的保留名称 States.ALL 是一个通配符,与所有错误名称匹配。它必须单独显示在 ErrorEquals 数组中,并且必须显示在 Retry 数组的最后一个重试器中。该名称States.TaskFailed还充当通配符,可匹配除以下以外的任何错误States.Timeout

Retry 字段的此示例重试 States.Timeout 之外的任意错误。

"Retry": [ { "ErrorEquals": [ "States.Timeout" ], "MaxAttempts": 0 }, { "ErrorEquals": [ "States.ALL" ] } ]

复杂重试场景

在单状态执行的上下文中,重试器的参数应用到对该重试器的所有访问。

考虑以下 Task 状态。

"X": { "Type": "Task", "Resource": "arn:aws:states:us-east-1:123456789012:task:X", "Next": "Y", "Retry": [ { "ErrorEquals": [ "ErrorA", "ErrorB" ], "IntervalSeconds": 1, "BackoffRate": 2.0, "MaxAttempts": 2 }, { "ErrorEquals": [ "ErrorC" ], "IntervalSeconds": 5 } ], "Catch": [ { "ErrorEquals": [ "States.ALL" ], "Next": "Z" } ] }

此任务连续四次失败,输出以下错误名称:ErrorAErrorBErrorC、和ErrorB。出现以下结果:

  • 前两个错误与第一个重试器相匹配,会导致等待一秒和两秒钟。

  • 第三个错误与第二个重试器相匹配,导致等待五秒钟。

  • 第四个错误也与第一个重试器相匹配。但是,对于该特定错误,它已经达到了重试两次 (MaxAttempts) 的最大值。因此,该检索器失败,执行将通过该Catch字段将工作流重定向到该Z状态。

备用状态

TaskMap并且每个Parallel状态都可以有一个名为的字段Catch。此字段的值必须是称为捕获器 的对象的数组。

捕获器包含以下字段。

ErrorEquals (必需)

一个与错误名称匹配的非空字符串数组,由相同名称的重试器字段完全按其原样指定。

Next (必需)

一个字符串,必须与状态机的状态名称之一完全匹配。

ResultPath(可选)

一条路径,用于确定捕手将哪些输入发送到Next字段中指定的状态。

当某个状态报告错误并且没有Retry字段,或者重试无法解决错误时,Step Functions 会按照数组中列出的顺序扫描捕获器。当错误名称显示在捕获器的 ErrorEquals 字段中时,状态机转换为在 Next 字段中指定的状态。

捕获器的 ErrorEquals 字段中显示的保留名称 States.ALL 是一个通配符,与所有错误名称匹配。它必须单独显示在 ErrorEquals 数组中,并且必须显示在 Catch 数组的最后一个捕获器中。该名称States.TaskFailed还充当通配符,可匹配除以下以外的任何错误States.Timeout

以下示例显示,当 Lambda 函数输出未处理的 Java 异常RecoveryState时,Catch字段会转换为名为的状态。否则,该字段转换为 EndState 状态。

"Catch": [ { "ErrorEquals": [ "java.lang.Exception" ], "ResultPath": "$.error-info", "Next": "RecoveryState" }, { "ErrorEquals": [ "States.ALL" ], "Next": "EndState" } ]
注意

每个捕获器可以指定多个要处理的错误。

错误输出

当 Step Functions 过渡到catch 名称中指定的状态时,对象通常包含该字段Cause。此字段的值是人类可读格式的错误说明。该对象称为错误输出

在本示例中,第一个捕获器包含一个 ResultPath 字段。其工作方式类似于状态顶级中的 ResultPath 字段,有两种可能的结果:

  • 它获取该状态的执行结果并覆盖该状态的全部或部分输入。

  • 它获取结果并将其添加到输入中。如果错误由捕获器处理,则状态执行的结果是错误输出。

因此,对于示例中的第一个捕获器,error-info如果输入中还没有具有此名称的字段,则捕手会将错误输出作为名为的字段添加到输入中。然后,捕手将全部输入发送到RecoveryState。对于第二个捕获器,错误输出会覆盖输入,捕获器仅将错误输出发送到EndState

注意

如果您不指定 ResultPath 字段,则它会默认为 $,这会选择和覆盖整个输入。

当状态同时包含RetryCatch字段时,Step Functions 会首先使用任何相应的检索器。如果重试策略无法解决错误,Step Functions 会应用匹配的捕手转换。

导致有效载荷和服务集成

捕手返回字符串有效负载作为输出。在使用 Amazon Athena 等服务集成时Amazon CodeBuild,您可能需要将Cause字符串转换为 JSON。以下带有内部函数的Pass状态示例显示了如何将Cause字符串转换为 JSON。

"Handle escaped JSON with JSONtoString": { "Type": "Pass", "Parameters": { "Cause.$": "States.StringToJson($.Cause)" }, "Next": "Pass State with Pass Processing" },

使用重试和使用 Catch 的示例

以下示例中定义的状态机假设存在两个 Lambda 函数:一个总是失败,另一个等待足够长的时间以允许状态机中定义的超时发生。

这是 Node.js Lambda 函数的定义,该函数总是失败并返回消息error。在随后的状态机示例中,此 Lambda 函数被命名为FailFunction。有关创建 Lambda 函数的信息,请参阅步骤 1:创建 Lambda 函数部分。

exports.handler = (event, context, callback) => { callback("error"); };

这是睡眠 10 秒钟的 Node.js Lambda 函数的定义。在随后的状态机示例中,此 Lambda 函数被命名为sleep10

注意

在 Lambda 控制台中创建此 Lambda 函数时,请记住将高级设置部分中的超时值从 3 秒(默认)更改为 11 秒。

exports.handler = (event, context, callback) => { setTimeout(function(){ }, 11000); };

使用 “重试” 处理故障

此状态机使用 Retry 字段重试失败的函数,并输出错误名称 HandledError。它重试此函数两次,在两次重试之间以指数回退。

{ "Comment": "A Hello World example of the Amazon States Language using an Amazon Lambda function", "StartAt": "HelloWorld", "States": { "HelloWorld": { "Type": "Task", "Resource": "arn:aws:lambda:us-east-1:123456789012:function:FailFunction", "Retry": [ { "ErrorEquals": ["HandledError"], "IntervalSeconds": 1, "MaxAttempts": 2, "BackoffRate": 2.0 } ], "End": true } } }

此变体使用预定义的错误代码States.TaskFailed,该代码与 Lambda 函数输出的任何错误相匹配。

{ "Comment": "A Hello World example of the Amazon States Language using an Amazon Lambda function", "StartAt": "HelloWorld", "States": { "HelloWorld": { "Type": "Task", "Resource": "arn:aws:lambda:us-east-1:123456789012:function:FailFunction", "Retry": [ { "ErrorEquals": ["States.TaskFailed"], "IntervalSeconds": 1, "MaxAttempts": 2, "BackoffRate": 2.0 } ], "End": true } } }
注意

作为最佳实践,引用 Lambda 函数的任务应处理 Lambda 服务异常。有关更多信息,请参阅处理 Lambda 服务异常

使用 Catch 处理故障

此示例使用 Catch 字段。当 Lambda 函数输出错误时,它会捕获错误,然后状态机过渡到fallback状态。

{ "Comment": "A Hello World example of the Amazon States Language using an Amazon Lambda function", "StartAt": "HelloWorld", "States": { "HelloWorld": { "Type": "Task", "Resource": "arn:aws:lambda:us-east-1:123456789012:function:FailFunction", "Catch": [ { "ErrorEquals": ["HandledError"], "Next": "fallback" } ], "End": true }, "fallback": { "Type": "Pass", "Result": "Hello, Amazon Step Functions!", "End": true } } }

此变体使用预定义的错误代码States.TaskFailed,该代码与 Lambda 函数输出的任何错误相匹配。

{ "Comment": "A Hello World example of the Amazon States Language using an Amazon Lambda function", "StartAt": "HelloWorld", "States": { "HelloWorld": { "Type": "Task", "Resource": "arn:aws:lambda:us-east-1:123456789012:function:FailFunction", "Catch": [ { "ErrorEquals": ["States.TaskFailed"], "Next": "fallback" } ], "End": true }, "fallback": { "Type": "Pass", "Result": "Hello, Amazon Step Functions!", "End": true } } }

使用 “重试” 处理超时

此状态机使用Retry字段根据中指定的超时值重试超时的Task状态TimeoutSeconds。Step Functions 在此Task状态下重试 Lambda 函数调用两次,重试之间呈指数级退缩。

{ "Comment": "A Hello World example of the Amazon States Language using an Amazon Lambda function", "StartAt": "HelloWorld", "States": { "HelloWorld": { "Type": "Task", "Resource": "arn:aws:lambda:us-east-1:123456789012:function:sleep10", "TimeoutSeconds": 2, "Retry": [ { "ErrorEquals": ["States.Timeout"], "IntervalSeconds": 1, "MaxAttempts": 2, "BackoffRate": 2.0 } ], "End": true } } }

使用 Catch 处理超时

此示例使用 Catch 字段。在出现超时的情况下,状态机会转换为 fallback 状态。

{ "Comment": "A Hello World example of the Amazon States Language using an Amazon Lambda function", "StartAt": "HelloWorld", "States": { "HelloWorld": { "Type": "Task", "Resource": "arn:aws:lambda:us-east-1:123456789012:function:sleep10", "TimeoutSeconds": 2, "Catch": [ { "ErrorEquals": ["States.Timeout"], "Next": "fallback" } ], "End": true }, "fallback": { "Type": "Pass", "Result": "Hello, Amazon Step Functions!", "End": true } } }
注意

可以通过使用 ResultPath 来保留状态输入以及错误。请参阅 ResultPath 用于在 a 中同时包含错误和输入Catch