AWS Step Functions
开发人员指南
AWS 文档中描述的 AWS 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 AWS 服务入门

错误处理

任何状态都可能会遇到运行时错误。错误可能由于各种原因发生:

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

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

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

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

错误名称

Step Functions 使用称为错误名称 的区分大小写的字符串在 Amazon 状态语言中标识错误。Amazon 状态语言定义一组内置字符串用于命名广为人知的错误,均以 States. 前缀开头。

States.ALL

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

States.Timeout

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

States.TaskFailed

一个在执行期间失败的 Task 状态。

States.Permissions

一个 Task 状态,该状态由于没有足够的权限执行指定代码而失败。

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

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

注意

Lambda 中未处理的错误在错误输出中报告为 Lambda.Unknown。这些包括内存不足错误、函数超时,以及达到并发 Lambda 调用限制。您可以根据 Lambda.UnknownStates.ALLStates.TaskFailed 比对来处理这些错误。有关 Lambda HandledUnhandled 错误的更多信息,请参阅AWS Lambda Developer Guide中的 FunctionError

出错后重试

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

注意

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

重试器包含以下字段。

ErrorEquals (必需)

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

IntervalSeconds(可选)

一个整数,表示第一次重试尝试之前等待的秒数 (默认值为 1)。

MaxAttempts(可选)

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

BackoffRate(可选)

每次重试之间,重试时间间隔增长的倍数 (默认值为 2.0)。

Retry 示例在等待 3 秒和 4.5 秒之后,尝试 2 次重试。

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

重试器的 ErrorEquals 字段中显示的保留名称 States.ALL 是一个通配符,与所有错误名称匹配。它必须单独显示在 ErrorEquals 数组中,并且必须显示在 Retry 数组的最后一个重试器中。

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

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

复杂的重试场景

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

考虑以下 Task 状态:

"X": { "Type": "Task", "Resource": "arn:aws-cn: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" } ] }

此任务连续失败五次,输出以下错误名称:ErrorAErrorBErrorCErrorBErrorB。出现以下结果:

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

  • 第三个错误与第二个重试器匹配,导致等待 5 秒:

  • 第四个错误与第一个重试器匹配,导致等待 4 秒:

  • 第五个错误也与第一个重试器匹配。但是,它已经达到了该特定错误 (ErrorB) 上两次重试 (MaxAttempts) 的限制,因此失败,并通过 Catch 字段将执行重定向到 Z 状态。

回退状态

TaskParallel 状态可以具有名为 Catch 的字段。此字段的值必须是称为捕获器 的对象的数组。

捕获器包含以下字段。

ErrorEquals (必需)

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

Next (必需)

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

ResultPath(可选)

一个路径,确定将什么输入发送到 Next 字段中指定的状态。

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

捕获器的 ErrorEquals 字段中显示的保留名称 States.ALL 是一个通配符,与所有错误名称匹配。它必须单独显示在 ErrorEquals 数组中,并且必须显示在 Catch 数组的最后一个捕获器中。

以下示例说明的是一个 Catch 字段,该字段在 Lambda 函数输出未处理的 Java 异常时转换为名为 RecoveryState 的状态。否则,该字段转换为 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 首先使用任意合适的重试器,只有在重试策略无法解决错误之后才应用匹配的捕获器转换。

使用 Retry 和使用 Catch 的示例

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

这是始终失败的 Lambda 函数的定义,返回消息 error。在后面的状态机示例中,此 Lambda 函数名为 FailFunction

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

这是一个休眠 10 秒的 Lambda 函数的定义。在后面的状态机示例中,此 Lambda 函数名为 sleep10

注意

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

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

使用 Retry 处理失败

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

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

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

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

使用 Retry 处理超时

此状态机使用 Retry 字段重试已超时的函数。该函数重试两次,在两次重试之间使用指数回退。

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

注意

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