从您的要求“我的要求是检查并行机的最终执行状态,如果有任何故障,调用SNS服务发送电子邮件。”,我理解“failtask”只是为了调试目的和将来它不一定会失败。所以问题是,当 Step Functions 检测到一个分支中的故障时,所有其他分支都被终止并且它们的输出被丢弃,只有故障分支的输出被使用。因此,如果要保留每个分支的输出并检查是否发生故障,则需要处理每个分支中的错误,而不是将整个分支报告为失败。此外,您需要向每个分支添加一个输出字段,说明是否存在故障(如果字段不存在,Choice State 将给出错误)。还要记住,ParralelState 的输出是一个包含每个分支输出的数组,例如这个状态机应该让每个分支完成执行并正确处理错误:
{
"Comment": "Parallel Example",
"StartAt": "Parallel Task",
"TimeoutSeconds": 120,
"States": {
"Parallel Task": {
"Type": "Parallel",
"Branches": [{
"StartAt": "passtask",
"States": {
"passtask": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:XXXXXXXXXXXXXXXXX",
"Next": "SuccessBranch1",
"Catch": [{
"ErrorEquals": ["States.ALL"],
"Next": "FailBranch1"
}]
},
"SuccessBranch1": {
"Type": "Pass",
"Result": {
"Error": false
},
"ResultPath": "$.Status",
"End": true
},
"FailBranch1": {
"Type": "Pass",
"Result": {
"Error": true
},
"ResultPath": "$.Status",
"End": true
}
}
},
{
"StartAt": "failtask",
"States": {
"failtask": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:XXXXXXXXXXXXXXXXX",
"Next": "SuccessBranch2",
"Catch": [{
"ErrorEquals": ["States.ALL"],
"Next": "FailBranch2"
}]
},
"SuccessBranch2": {
"Type": "Pass",
"Result": {
"Error": false
},
"ResultPath": "$.Status",
"End": true
},
"FailBranch2": {
"Type": "Pass",
"Result": {
"Error": true
},
"ResultPath": "$.Status",
"End": true
}
}
}
],
"ResultPath": "$.ParralelOutput",
"Catch": [{
"Comment": "This catch should never catch any errors, as the error handling is done in the individual Branches",
"ErrorEquals": ["States.ALL"],
"ResultPath": "$.ParralelOutput",
"Next": "ChoiceStateX"
}],
"Next": "ChoiceStateX"
},
"ChoiceStateX": {
"Type": "Choice",
"Choices": [{
"Or": [{
"Variable": "$.ParralelOutput[0].Status.Error",
"BooleanEquals": true
},
{
"Variable": "$.ParralelOutput[1].Status.Error",
"BooleanEquals": true
}
],
"Next": "Notify Failure"
}],
"Default": "Notify Success"
},
"Notify Failure": {
"Type": "Pass",
"End": true
},
"Notify Success": {
"Type": "Pass",
"Result": "This is a fallback from a task success",
"End": true
}
}
}
对于 Nisman 在 cmets 中提出的上述更一般的情况(尽管更复杂)。我们可以添加一个带有一些 JSONPath 技巧的通过状态,而不是硬编码选择状态来检查每个分支,以检查当前仅使用选择状态无法实现的条件。
在这个 Pass State 中,我们使用参数来重组我们的数据,这样当我们使用 OutputPath 对这个数据应用 JSONPath 过滤器表达式时,我们会得到一个 2(如果没有分支失败)或 3(如果某些分支失败)元素,其中第一个元素始终包含原始输入数据,第二个/第三个元素至少包含一个同名的键,供选择状态使用。这是状态机 JSON:
{
"Comment": "Parallel Example",
"StartAt": "Parallel Task",
"States": {
"Parallel Task": {
"Type": "Parallel",
"Branches": [
{
"StartAt": "passtask",
"States": {
"passtask": {
"Type": "Task",
"Resource": "<TASK RESOURCE>",
"End": true,
"Catch": [
{
"ErrorEquals": [
"States.ALL"
],
"ResultPath": "$.error-info",
"Next": "FailBranch1"
}
]
},
"FailBranch1": {
"Type": "Pass",
"Parameters": {
"BranchOutput.$": "$",
"BranchError": true
},
"End": true
}
}
},
{
"StartAt": "failtask",
"States": {
"failtask": {
"Type": "Task",
"Resource": "<TASK RESOURCE>",
"End": true,
"Catch": [
{
"ErrorEquals": [
"States.ALL"
],
"ResultPath": "$.error-info",
"Next": "FailBranch2"
}
]
},
"FailBranch2": {
"Type": "Pass",
"Parameters": {
"BranchOutput.$": "$",
"BranchError": true
},
"End": true
}
}
}
],
"ResultPath": "$.ParralelOutput",
"Next": "Pre-Process"
},
"Pre-Process": {
"Type": "Pass",
"Parameters": {
"OrderedArray": [
{
"OriginalData": {
"Input.$": "$",
"ShouldFilterData": false
}
},
{
"ValuesToCheck": {
"ListBranchErrors.$": "$.ParralelOutput[?(@.BranchError==true)].BranchError",
"BranchFailures": true
}
},
{
"DefaultAlwaysFalse": {
"ShouldFilterData": false,
"BranchFailures": false
}
}
]
},
"OutputPath": "$..[?(@.ShouldFilterData == false || @.ListBranchErrors[0] == true)]",
"Next": "ChoiceStateX"
},
"ChoiceStateX": {
"Type": "Choice",
"OutputPath": "$.[0].Input",
"Choices": [
{
"Variable": "$[1].BranchFailures",
"BooleanEquals": true,
"Next": "NotifyFailure"
},
{
"Variable": "$[1].BranchFailures",
"BooleanEquals": false,
"Next": "NotifySuccess"
}
],
"Default": "NotifyFailure"
},
"NotifyFailure": {
"Type": "Pass",
"End": true
},
"NotifySuccess": {
"Type": "Pass",
"Result": "This is a fallback from a task success",
"End": true
}
}
}