将 AWS Step Function 转换为使用 CDK - 第 1 部分
如果您喜欢流畅的编码,那么AWS 云开发工具包步骤函数定义就在您的街道上。然而,事情并不像你想象的那么简单。 在我之前的文章使用适用于 VS 代码的 AWS 工具包的更简单的步骤函数中,我赞扬了将 AWS 工具包与AWS 无服务器应用程序模型 (SAM)结合使用的优点。现在,我将提出一种完全不同的做事方式。 这篇文章假设您对 CDK 有一定的了解。如果您不是,那么AWS CDK 入门指南是最好的起
如果您喜欢流畅的编码,那么AWS 云开发工具包步骤函数定义就在您的街道上。然而,事情并不像你想象的那么简单。
在我之前的文章使用适用于 VS 代码的 AWS 工具包的更简单的步骤函数中,我赞扬了将 AWS 工具包与AWS 无服务器应用程序模型 (SAM)结合使用的优点。现在,我将提出一种完全不同的做事方式。
这篇文章假设您对 CDK 有一定的了解。如果您不是,那么AWS CDK 入门指南是最好的起点。指南中的以下引用很好地概述了 CDK 背后的关键概念。
"AWS CDK 应用程序是用 TypeScript、JavaScript、Python、Java 或 C# 编写的应用程序,它使用 AWS CDK 定义 AWS 基础设施。应用程序定义一个或多个堆栈。堆栈(相当于 AWS CloudFormation 堆栈)包含构造,每个都定义了一个或多个具体的 AWS 资源,例如 Amazon S3 存储桶、Lambda 函数、Amazon DynamoDB 表等。”
对于这篇文章,我复制了原始的基于 SAM 的repo,然后将其修改为使用 CDK。结果可以在这里找到。
CDK 中的步骤函数需要引用它们调用的函数。在演示项目中,所有函数都在同一个文件中并遵循命名约定。这使我能够在Stack
类中创建以下方法:
private addFunction(functionName: string): lambda.Function {
return new lambdaNodejs.NodejsFunction(this, `${functionName}Function`, {
entry: path.join(__dirname, '..', 'src', 'functions', 'index.ts'),
handler: `handle${functionName}`,
});
}
有了这个,我就可以声明所有必需的函数,如下所示:
const performIdentityCheckFunction = this.addFunction('PerformIdentityCheck');
const aggregateIdentityResultsFunction = this.addFunction('AggregateIdentityResults');
const performAffordabilityCheckFunction = this.addFunction('PerformAffordabilityCheck');
const sendEmailFunction = this.addFunction('SendEmail');
const notifyUnderwriterFunction = this.addFunction('NotifyUnderwriter');
我现在可以将注意力转向转换阶跃函数本身。 step 函数是处理贷款申请的简化流程。第一步对每个申请人进行身份检查,然后汇总结果
对于 SAM,这是使用以下 YAML 定义的:
PerformIdentityChecks:
Type: Map
InputPath: "$.application"
ItemsPath: "$.applicants"
ResultPath: "$.identityResults"
Iterator:
StartAt: PerformIdentityCheck
States:
PerformIdentityCheck:
Type: Task
Resource: "${PerformIdentityCheckFunctionArn}"
End: true
Next: AggregateIdentityResults
AggregateIdentityResults:
Type: Task
Resource: "${AggregateIdentityResultsFunctionArn}"
InputPath: "$.identityResults"
ResultPath: "$.overallIdentityResult"
Next: EvaluateIdentityResults
CDK 使用流利的语法,其属性与上述匹配。我想很简单,只需在 TypeScript 中复制相同的逻辑即可:
const processApplicationStateMachine = new sfn.StateMachine(
this,
'ProcessApplicationStateMachine',
{
definition: sfn.Chain.start(
new sfn.Map(this, 'PerformIdentityChecks', {
inputPath: '$.application',
itemsPath: '$.applicants',
resultPath: '$.identityResults',
})
.iterator(
new sfnTasks.LambdaInvoke(this, 'PerformIdentityCheck', {
lambdaFunction: performIdentityCheckFunction,
})
)
.next(
new sfnTasks.LambdaInvoke(this, 'AggregateIdentityResults', {
lambdaFunction: aggregateIdentityResultsFunction,
inputPath: '$.identityResults',
resultPath: '$.overallIdentityResult',
})
)
),
}
);
下一步是让我测试它。使用 AWS Toolkit,我右键单击 step 函数并使用项目中的 JSON 测试文件之一。
然后我进入 AWS 控制台,很高兴看到它全是绿色的。
然而... 查看 PerformIdentityCheck 的步骤输出,我看到了以下输出:
{
"ExecutedVersion": "$LATEST",
"Payload": {
"success": false
},
"SdkHttpMetadata": {
<snip>
},
"SdkResponseMetadata": {
"RequestId": "76e41976-672d-4be0-a4d2-a5b80e7f9afe"
},
"StatusCode": 200
}
这不是我所期望的,但是通过使用函数上的outputPath
属性来选择Payload
可以很容易地解决这个问题。例如。:
new sfnTasks.LambdaInvoke(this, 'PerformIdentityCheck', {
lambdaFunction: performIdentityCheckFunction,
outputPath: '$.Payload',
})
有了这个改变,我再次部署,并启动了我的测试。结果......彻底失败。
我检查了 PerformIdentityCheck 步骤的输出,一切都符合预期,我检查了 map 步骤的输出,一切都符合预期。
问题出在 AggregateIdentityResults 上。它已按预期执行,输出以下内容。
{
"resourceType": "lambda",
"resource": "invoke",
"output": {
"ExecutedVersion": "$LATEST",
"Payload": false,
<snip>
"StatusCode": 200
},
"outputDetails": {
"truncated": false
}
}
但是,执行后会抛出Invalid path '$.Payload' : No results for path: $['Payload']
错误。
{
"error": "States.Runtime",
"cause": "An error occurred while executing the state 'AggregateIdentityResults' (entered at the event id #13). Invalid path '$.Payload' : No results for path: $['Payload']"
}
提示浪费了一个小时试图弄清楚为什么$.Payload
为一个功能任务工作,而不是另一个。我最终确实找到了这一点(见帖子末尾),但我的调查导致我从 2020 年 4 月开始出现以下问题:RunLambdaTask with outputPath not working
这为我指明了解决方案的方向。这是使用文档定义的payloadResponseOnly
属性,如下所示:
'以仅返回有效负载响应而没有其他元数据的方式调用 Lambda。
例如。:
new sfnTasks.LambdaInvoke(this, 'PerformIdentityCheck', {
lambdaFunction: performIdentityCheckFunction,
payloadResponseOnly: true,
})
有了这个,我重新运行了测试,并在 AWS 中检查了结果。
{
"application": {
<snip>
},
"identityResults": [
{
"success": false
}
],
"overallIdentityResult": false
}
**万岁!**这完全符合预期,函数调用没有返回无关数据。
通过查看生成的定义,我确实注意到,用于调用函数的生成 ASL 取决于payloadResponseOnly
的值。没有payloadResponseOnly: true
的定义如下生成:
"AggregateIdentityResults": {
<snap>
"Resource": "arn:aws:states:::lambda:invoke",
"Parameters": {
"FunctionName": "arn:aws:lambda:eu-west-2:361728023653:function:ProcessApplicationStack-AggregateIdentityResultsFu-B7MG7QWC1VLN",
"Payload.$": "$"
}
}
在使用payloadResponseOnly: true
时,我们得到以下与基于 SAM 的原始定义相匹配的内容:
"AggregateIdentityResults": {
<snip>
"Resource": "arn:aws:lambda:eu-west-2:361728023653:function:ProcessApplicationStack-AggregateIdentityResultsFu-B7MG7QWC1VLN"
}
这种差异一定是响应差异的原因,但我不知道为什么会这样。但是,我现在可以得到我想要的结果,所以我将继续前进。
这部分结束了,我预计会更进一步,但这个结果对于软件开发来说是相当标准的。在第 2 部分中,我将继续将 step 函数转换为 CDK,并记录我在此过程中遇到的挑战。
编辑:Payload
错误的原因是由于我对路径的处理方式有误解。我缺少的关键位如下:
“OutputPath 是在应用 ResultPath 后计算的。所有服务集成都返回元数据作为其响应的一部分。使用 ResultPath 时,无法将任务输出的子集合并到输入。”
更多推荐
所有评论(0)