本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
Step Functions 中的错误处理
任何状态都可能会遇到运行时错误。错误可能由于各种原因发生:
-
状态机定义问题(例如,
Choice
状态中没有匹配规则) -
任务失败(例如,Lambda 函数中的异常)
-
临时性问题(例如,网络分区事件)
默认情况下,当某个状态报告错误时,Amazon Step Functions 会导致执行完全失败。
错误名称
Step Functions 使用称为区分大小写的字符串在亚马逊状态语言中标识错误错误名称. 亚马逊状态语言定义一组内置字符串用于命名广为人知的错误,均以States.
prefix.
-
States.ALL
-
一个与任何已知错误名称匹配的通配符。
-
States.DataLimitExceeded
-
一个
States.DataLimitExceeded
以下情况将抛出异常:-
当连接器的输出大于有效负载大小配额时。
-
当状态的输出大于有效负载大小配额时。
-
什么时候,之后
Parameters
处理时,状态的输入大于有效负载大小配额。
有关配额的更多信息,请参阅。配额.
-
States.Runtime
-
由于某些无法处理的异常,执行失败。这些通常是由运行时的错误引起的,例如尝试在 null JSON 有效负载上应用
InputPath
或OutputPath
。States.Runtime
错误不可检索,并且始终会导致执行失败。在States.ALL
上重试或捕获不会捕获States.Runtime
错误。 -
States.HeartbeatTimeout
-
一个
Task
一段时间长度超过状态发送检测信号的时间长度HeartbeatSeconds
值。 -
States.Timeout
-
一个
Task
状态,该状态要么运行时间长度超过TimeoutSeconds
值,要么在超过HeartbeatSeconds
值的时段长度中未能发送检测信号。 -
States.TaskFailed
-
一个在执行期间失败的
Task
状态。在重试或 catch 中使用时,States.TaskFailed
用作与任意已知错误名称匹配的通配符,但以下情况除外:States.Timeout
. -
States.Permissions
-
一个
Task
状态,该状态由于没有足够的权限执行指定代码而失败。
状态可以报告具有其他名称的错误。但是,这些名称不得 States.
前缀开头。
作为最佳实践,确保生产代码可以处理 Amazon Lambda 服务异常(Lambda.ServiceException
和 Lambda.SdkClientException
)。有关更多信息,请参阅处理 Lambda 服务异常。
Lambda 中未处理的错误被报告为Lambda.Unknown
在错误输出中。这包括内存不足错误和函数超时。你可以在Lambda.Unknown
、States.ALL
,或者States.TaskFailed
来处理这些错误。当 Lambda 达到最大调用次数时,错误是Lambda.TooManyRequestsException
. 有关 Lambda 的更多信息Handled
和Unhandled
错误,请参阅FunctionError
中的Amazon Lambda开发人员指南.
出错后重试
Task
和 Parallel
状态可以有名为 Retry
的字段,其值必须是称为重试器 的对象的数组。一个重试器表示特定重试次数,通常重试之间的时间间隔会增加。
重试次数被视为状态转换。有关状态转换如何影响账单的信息,请参阅。Step Functions 定价
重试器包含以下字段。
-
ErrorEquals
(必需) -
一个匹配错误名称的非空字符串数组。当某个状态报告错误时,Step Functions 会全面地扫描重试器。当错误名称出现在此数组中时,它实施该重试器描述的重试策略。
-
IntervalSeconds
(可选) -
一个整数,表示第一次重试尝试之前等待的秒数 (
1
默认情况下)。IntervalSeconds
具有的最大值为99999999
. -
MaxAttempts
(可选) -
一个正整数,表示重试的最大次数 (默认值为
3
)。如果错误重复发生超过指定次数,则停止重试并恢复正常错误处理。值为0
指定永不重试错误。MaxAttempts
具有的最大值为99999999
. -
BackoffRate
(可选) -
每次重试之间,重试时间间隔增长的倍数 (默认值为
2.0
)。
此 Retry
示例在等待 3 秒和 4.5 秒之后,尝试 2 次重试。
"Retry": [ {
"ErrorEquals": [ "States.Timeout" ],
"IntervalSeconds": 3,
"MaxAttempts": 2,
"BackoffRate": 1.5
} ]
重试器的 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
和 ErrorB
。出现以下结果:
-
前两个错误与第一个重试器匹配,导致等待 1 秒和 2 秒。
-
第三个错误与第二个重试器匹配,导致等待 5 秒:
-
第四个错误与第一个重试器匹配,导致等待 4 秒:
-
第五个错误也与第一个重试器匹配。但是,它已经达到了该特定错误 (
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
.
以下示例为Catch
字段转换为名为的状态RecoveryState
当 Lambda 函数输出未处理的 Java 异常时。否则,该字段转换为 EndState
状态。
"Catch": [ {
"ErrorEquals": [ "java.lang.Exception" ],
"ResultPath": "$.error-info",
"Next": "RecoveryState"
}, {
"ErrorEquals": [ "States.ALL" ],
"Next": "EndState"
} ]
每个捕获器可以指定多个要处理的错误。
错误输出
当 Step Functions 转换为捕获名称中指定的状态时,对象通常包含字段。Cause
. 此字段的值是人类可读格式的错误说明。该对象称为错误输出。
在本示例中,第一个捕获器包含一个 ResultPath
字段。其工作方式类似于状态顶级中的 ResultPath
字段,有两种可能的结果:
-
它获取状态执行的结果并覆盖状态的部分输入 (或者状态的整个输入)。
-
它获取结果并将其添加到输入中。在由捕获器处理错误时,状态执行的结果是错误输出。
因此,在本示例中,对于第一个捕获器,错误输出作为名为 error-info
的字段添加到输入 (如果输入中尚未存在具有此名称的字段)。然后,整个输入发送到 RecoveryState
。对于第二个捕获器,错误输出会覆盖输入,仅将错误输出发送到 EndState
。
如果您不指定 ResultPath
字段,则它会默认为 $
,这会选择和覆盖整个输入。
当一个州有两者时Retry
和Catch
字段中,Step Functions 首先使用任意合适的重试器,只有在重试策略无法解决错误之后才应用匹配的捕获器转换。
导致有效负载和服务集成
捕手返回字符串有效负载作为输出。使用诸如 Amazon Athena 等服务集成时,或Amazon CodeBuild,您可能需要转换Cause
字符串转换为 JSON。以下带有内部函数的 Pass 状态示例说明了如何将原因字符串转换为 JSON。
"Handle escaped JSON with JSONtoString": {
"Type": "Pass",
"Parameters": {
"Cause.$": "States.StringToJson($.Cause)"
},
"Next": "Pass State with Pass Processing"
},
使用重试和使用 Catch 的示例
以下示例中定义的状态机假定存在两个 Lambda 函数:一个始终失败,另一个等待足够长的时间,以允许发生状态机中定义的超时。
这是始终失败的 Lambda 函数的定义,返回消息。error
. 在后面的状态机示例中,此 Lambda 函数名为FailFunction
.
exports.handler = (event, context, callback) => {
callback("error");
};
这是一个休眠 10 秒的 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
字段重试已超时的函数。该函数重试两次,在两次重试之间使用指数回退。
{
"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 在 Catch 中包含错误和输入。