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

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

Step Functions 中的错误处理

Pass和状态之外的所有Wait状态都可能遇到运行时错误。错误可能由于各种原因而发生,例如以下示例:

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

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

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

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

提示

要将包含错误处理的工作流程示例部署到您的中Amazon Web Services 账户,请参阅模块 8-Amazon Step Functions研讨会的错误处理

错误名称

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

States.ALL

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

注意

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

States.DataLimitExceeded

在以下情况下,Step Functions 会报告States.DataLimitExceeded异常:

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

  • 当状态的输出大于有效载荷大小配额时。

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

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

注意

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

States.ExceedToleratedFailureThreshold

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错误不可重复,并且总是会导致执行失败。重试或 catch on States.ALL 不会捕获States.Runtime错误。

States.TaskFailed

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

States.Timeout

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

此外,如果状态机的运行时间超过指定TimeoutSeconds值,则执行失败并States.Timeout显示错误。

状态可以报告具有其他名称的错误。但是,这些错误名称不能以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、和 st Map ates 可以有一个名为的字段Retry,其值必须是称为检索者的对象数组。一个重试器表示特定重试次数,通常重试之间的时间间隔会增加。

注意

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

重试器包含以下字段:

ErrorEquals (必需)

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

IntervalSeconds(可选)

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

MaxAttempts(可选)

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

BackoffRate(可选)

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

例如,假设你的IntervalSeconds是 3,MaxAttempts是 3,BackoffRate是 2。第一次重试是在错误发生三秒钟后进行的。第二次重试发生在第一次重试六秒钟后。而第三次重试发生在第二次重试尝试 12 秒后。

MaxDelaySeconds(可选)

一个正整数,用于设置最大值(以秒为单位),重试间隔最多可以增加到该值。此字段对于与该BackoffRate字段一起使用很有帮助。您在此字段中指定的值限制了因应用于每次连续重试尝试的退避率乘数而产生的指数等待时间。必须为指定一个大于 0 且小于 31622401 的值。MaxDelaySeconds

如果您未指定此值,则 Step Functions 不会限制两次重试之间的等待时间。

JitterStrategy(可选)

一个字符串,用于确定是否在连续重试尝试之间的等待时间中包含抖动。抖动通过在随机延迟间隔内分散重试次数来减少同时重试的尝试。此字符串接受FULLNONE作为其值。默认值为 NONE

例如,假设您已设置MaxAttempts为 3、设置IntervalSeconds为 2 和设置BackoffRate为 2。第一次重试是在错误发生两秒钟后进行的。第二次重试发生在第一次重试四秒后,第三次重试发生在第二次重试八秒后。如果设置JitterStrategyFULL,则第一个重试间隔在 0 到 2 秒之间随机化,第二个重试间隔在 0 到 4 秒之间随机化,第三个重试间隔在 0 到 8 秒之间随机化。

当状态报告错误并且有Retry字段时,Step Functions 会按照数组中列出的顺序扫描检索器。当错误名称出现在检索者字段的值中时,状态机将按照ErrorEquals字段中的定义进行重试尝试。Retry

重试字段示例

本节包括以下Retry字段示例。

提示

要将错误处理工作流程的示例部署到您的Amazon Web Services 账户,请参阅 The Worksho Amazon Step Functionsp 的错误处理模块。

示例 1-使用重试 BackoffRate

以下 a 的示例Retry进行了两次重试,第一次重试是在等待三秒钟后进行的。根据BackoffRate您指定的值,Step Functions 会增加每次重试之间的间隔,直到达到最大重试次数。在以下示例中,第二次重试是在第一次重试后等待三秒钟后开始的。

"Retry": [ { "ErrorEquals": [ "States.Timeout" ], "IntervalSeconds": 3, "MaxAttempts": 2, "BackoffRate": 1 } ]
示例 2-使用重试 MaxDelaySeconds

以下示例进行了三次重试尝试,并将由此产生的等待时间限制BackoffRate为 5 秒。第一次重试是在等待三秒钟后进行的。由于设置了最大等待时间限制,第二次和第三次重试是在前一次重试后等待五秒钟后进行的。MaxDelaySeconds

"Retry": [ { "ErrorEquals": [ "States.Timeout" ], "IntervalSeconds": 3, "MaxAttempts": 3, "BackoffRate":2, "MaxDelaySeconds": 5, "JitterStrategy": "FULL" } ]

MaxDelaySeconds则,第二次重试将在第一次重试 6 秒后进行,第三次重试将在第二次重试 12 秒后进行。

示例 3-重试除 States.Timeout 之外的所有错误

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

以下Retry字段示例会重试任何错误,但以下错误除外States.Timeout

"Retry": [ { "ErrorEquals": [ "States.Timeout" ], "MaxAttempts": 0 }, { "ErrorEquals": [ "States.ALL" ] } ]
示例 4-复杂的重试场景

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

考虑以下 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)。因此,该检索器失败,执行会通过该字段将工作流程重定向到Z状态。Catch

后备状态

TaskMapParallel州可以有一个名为的字段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 Amazon CodeBuild Athena 或之类的服务集成时,您可能需要将字符串Cause转换为 JSON。以下带有内部函数的Pass状态示例显示了如何将Cause字符串转换为 JSON。

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

使用 Retry 和 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 } } }

使用 “重试” 处理超时

根据中指定的超时值,此Task状态机使用Retry字段重试超时的状态。TimeoutSecondsStep 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