本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
Step Functions 中的错误处理
任何状态都可能会遇到运行时错误。错误的发生可能有多种原因,例如以下示例:
-
状态机定义问题(例如,
Choice
状态中没有匹配规则) -
任务失败(例如,Amazon Lambda 函数中的异常)
-
临时性问题(例如,网络分区事件)
默认情况下,当某个状态报告错误时,Amazon Step Functions 会导致执行完全失败。
要向您部署错误处理示例,请参阅 ThAmazon Web Services 账户 e Workshop 的模块 8-错误Amazon Step Functions处理
错误名称
Step Functions 使用区分大小写的字符串(称为错误名称)识别亚马逊状态语言中的错误。Amazon States 语言定义了一组命名众所周知错误的内置字符串,所有字符串都以States.
前缀开头。
-
States.ALL
-
一个与任何已知错误名称匹配的通配符。
注意 此错误类型无法catch
States.DataLimitExceeded
终端错误类型和运行时错误类型。有关这些错误类型的更多信息,请参阅States.DataLimitExceeded和States.Runtime。 -
States.BranchFailed
-
一个
Parallel
州的分支失败了。 -
States.DataLimitExceeded
-
在以下条件下,Step Functions 报告
States.DataLimitExceeded
异常:-
当连接器的输出大于有效负载大小配额时。
-
当状态的输出大于负载大小配额时。
-
Parameters
处理后,当状态的输入大于负载大小配额时。
有关配额的更多信息,请参阅配额。
注意 这是错误类型无法捕获的终端
States.ALL
错误。 -
States.ExceedToleratedFailureThreshold
Map
状态失败是因为失败项的数量超过了状态机定义中指定的阈值。有关更多信息,请参阅Map 状态的容许故障阈值:-
States.HeartbeatTimeout
-
Task
状态未能发送心跳的时间超过该HeartbeatSeconds
值。注意 此错误仅在
Catch
和Retry
字段中可用。 -
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 有效负载上应用
InputPath
或OutputPath
。States.Runtime
错误是不可检索的,并且总是会导致执行失败。重试或重试States.ALL
不会catchStates.Runtime
错误。 -
States.TaskFailed
-
一个在执行期间失败的
Task
状态。在重试或catch 中使用时,States.TaskFailed
充当通配符,可匹配除以下以外的任何已知错误名称States.Timeout
。 -
States.Timeout
-
一个
Task
状态,该状态要么运行时间长度超过TimeoutSeconds
值,要么在超过HeartbeatSeconds
值的时段长度中未能发送检测信号。
状态可以报告具有其他名称的错误。但是,这些错误名称不能以States.
前缀开头。
作为最佳实践,确保生产代码可以处理 Amazon Lambda 服务异常(Lambda.ServiceException
和 Lambda.SdkClientException
)。有关更多信息,请参阅处理 Lambda 服务异常:
Lambda 中未处理的错误如错误输出Lambda.Unknown
中所报告。其中包括 out-of-memory 错误和函数超时。您可以在Lambda.Unknown
States.ALL
、或上进行匹配States.TaskFailed
来处理这些错误。当 Lambda 达到最大调用次数时,错误为Lambda.TooManyRequestsException
。有关 Lambda 函数错误的更多信息,请参阅Amazon Lambda开发者指南中的错误处理和自动重试。
出错后重试
Task
和 Parallel
状态可以有名为 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
"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"
} ]
}
此任务连续四次失败,输出以下错误名称:ErrorA
ErrorB
、ErrorC
、和ErrorB
。出现以下结果:
-
前两个错误与第一个重试器相匹配,会导致等待一秒和两秒钟。
-
第三个错误与第二个重试器相匹配,导致等待五秒钟。
-
第四个错误也与第一个重试器相匹配。但是,对于该特定错误,它已经达到了重试两次 (
MaxAttempts
) 的最大值。因此,该检索器失败,执行将通过该Catch
字段将工作流重定向到该Z
状态。
备用状态
Task
,Map
并且每个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
字段,则它会默认为 $
,这会选择和覆盖整个输入。
当状态同时包含Retry
和Catch
字段时,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。