feat(stepfunctions-tasks): step functions task for cross-region AWS API call#30061
feat(stepfunctions-tasks): step functions task for cross-region AWS API call#30061mergify[bot] merged 11 commits intoaws:mainfrom
Conversation
aws-cdk-automation
left a comment
There was a problem hiding this comment.
The pull request linter has failed. See the aws-cdk-automation comment below for failure reasons. If you believe this pull request should receive an exemption, please comment and provide a justification.
A comment requesting an exemption should contain the text Exemption Request. Additionally, if clarification is needed add Clarification Request to a comment.
✅ Updated pull request passes all PRLinter validations. Dismissing previous PRLinter review.
...k/custom-resource-handlers/lib/aws-stepfunctions-tasks/cross-region-aws-sdk-handler/index.ts
Show resolved
Hide resolved
nmussy
left a comment
There was a problem hiding this comment.
Looks good overall, just some concerns and minor comments. I'm also wondering if it's better for maintainability not to create a new class, and to reuse the existing CallAwsService, and just to add an optional crossRegionTarget prop
...k/custom-resource-handlers/lib/aws-stepfunctions-tasks/cross-region-aws-sdk-handler/index.ts
Outdated
Show resolved
Hide resolved
...mework-integ/test/aws-stepfunctions-tasks/test/lambda/integ.call-aws-service-cross-region.ts
Show resolved
Hide resolved
...k/custom-resource-handlers/lib/aws-stepfunctions-tasks/cross-region-aws-sdk-handler/index.ts
Outdated
Show resolved
Hide resolved
|
|
||
| try { | ||
| // esbuild-disable unsupported-require-call -- not esbuildable but that's fine | ||
| const pkg = require(`@aws-sdk/client-${event.service}`); |
There was a problem hiding this comment.
Correct me if I'm wrong, but normalizeServiceName is not being ran for your handler? It would allow us to keep the same pattern as other services props, see AwsSdkCall:
There was a problem hiding this comment.
I'd like to keep this feature and API as simple as possible to lower the maintenance cost. AwsSdkCall code has become such complicated mostly for backward compatibility reason. Since this feature is new, we don't have to introduce the complexity at all.
Also the API is aimed to be compatible with the existing CallAwsService construct (and it should), which also does not support normalizing service names.
There was a problem hiding this comment.
I'll let the maintainer weigh in, I think it's a nice piece of QoL, but I understand your maintainability concern
There was a problem hiding this comment.
To help me understand, can you elaborate on your concern? What maintenance cost are you concerned with using AwsSdkCall code.
There was a problem hiding this comment.
AwsSdkCall's code is mainly to solve the v2-v3 compatibility problem. Since this construct does not require such compatibility, I think there is little advantage to using the existing code. After all, the new Lambda is only code under 100 lines. Also, if we want to reuse the existing code, we need to refactor it first (for example, currently it's only for CFn custom resource handler, but this one is for invocation from SFn). Given the ROI, I'd rather keep them independent.
| */ | ||
| export interface CallAwsServiceCrossRegionProps extends sfn.TaskStateBaseProps { | ||
| /** | ||
| * The AWS service to call in AWS SDK for JavaScript v3 style. |
There was a problem hiding this comment.
See comment about normalizeServiceName
| // esbuild-disable unsupported-require-call -- not esbuildable but that's fine | ||
| const pkg = require(`@aws-sdk/client-${event.service}`); | ||
| const Client = findV3ClientConstructor(pkg); | ||
| const Command = findCommandClass(pkg, event.action); |
There was a problem hiding this comment.
Similarly, you should be able to use normalizeActionName, see AwsSdkCall:
There was a problem hiding this comment.
Same as service name, I'd like to intentionally only support action names in camelCase.
| /** | ||
| * The API action to call. | ||
| * | ||
| * Use camelCase. |
There was a problem hiding this comment.
See comment about normalizeActionName
packages/aws-cdk-lib/aws-stepfunctions-tasks/lib/lambda/call-aws-service-cross-region.ts
Show resolved
Hide resolved
|
Hi @nmussy, thanks for the comments.
I considered this approach as well but chose the current approach, because with the current approach we can easily avoid from future breaking changes when SFn will officially start to support cross-region API call; we can just deprecate |
nmussy
left a comment
There was a problem hiding this comment.
LGTM, just a couple of pending comments
GavinZZ
left a comment
There was a problem hiding this comment.
Left some minor feedbacks. Also have a high-level questions I want to clarify on. There's already a stepfunctions task for CallAwsService. Is the reason of building this cross-region-aws-sdk-handler using custom resource lambda function because the AWS SDK service integrations do not support cross region invocation?
packages/aws-cdk-lib/aws-stepfunctions-tasks/lib/lambda/call-aws-service-cross-region.ts
Outdated
Show resolved
Hide resolved
| * | ||
| * @default - service:action | ||
| */ | ||
| readonly iamAction?: string; |
There was a problem hiding this comment.
Question: does it only support one single action? What would users do if I want to support multiple actions?
There was a problem hiding this comment.
In that case, you can use additionalIamStatements. I agree that this should ideally be iamActions?: string[], but then the API becomes less compatible with CallAwsService construct. I think it's okay to leave this as-is because most API only requires a single IAM action anyway. Wdyt?
There was a problem hiding this comment.
Can you share an example how to use additionalIamStatements with another action? I also think it would be nice to add this example to the readme file.
There was a problem hiding this comment.
Sure, but that is same as CallAwsService, which is described here:
aws-cdk/packages/aws-cdk-lib/aws-stepfunctions-tasks/README.md
Lines 233 to 245 in c826d8f
so I added a line as below:
Other properties such as
additionalIamStatementscan be used in the same way as theCallAwsServicetask.
packages/aws-cdk-lib/aws-stepfunctions-tasks/lib/lambda/call-aws-service-cross-region.ts
Show resolved
Hide resolved
packages/aws-cdk-lib/aws-stepfunctions-tasks/lib/lambda/call-aws-service-cross-region.ts
Show resolved
Hide resolved
|
|
||
| try { | ||
| // esbuild-disable unsupported-require-call -- not esbuildable but that's fine | ||
| const pkg = require(`@aws-sdk/client-${event.service}`); |
There was a problem hiding this comment.
To help me understand, can you elaborate on your concern? What maintenance cost are you concerned with using AwsSdkCall code.
|
Hi @GavinZZ, thank you so much for the review!
Yes. According to the doc:
|
|
Thank you for contributing! Your pull request will be updated from main and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork). |
|
Thank you for contributing! Your pull request will be updated from main and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork). |
|
Thank you for contributing! Your pull request will be updated from main and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork). |
AWS CodeBuild CI Report
Powered by github-codebuild-logs, available on the AWS Serverless Application Repository |
|
Thank you for contributing! Your pull request will be updated from main and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork). |
|
Comments on closed issues and PRs are hard for our team to see. If you need help, please open a new issue that references this one. |
Issue # (if applicable)
Closes #29918.
Reason for this change
It would be useful if we could call AWS API across regions from a Step Functions state machine. Currently it is not officially supported even with AWS SDK integration tasks.
Our usecase is to automate a cross-region failover scenario in a multi-region application. This requires you to orchestrate multiple API calls for both active and standby regions (e.g. failover Aurora DB cluster, rewrite AppConfig parameter, etc), and it would be great if we can manage these operations in a single state machine.
Description of changes
This PR adds a new construct
CallAwsServiceCrossRegionthat deploys 1. a Lambda function to call AWS API in different regions 2. SFn task to call the function.Because most properties are compatible with the existing
CallAwsServiceconstruct, you can use the new construct by just adding theregionproperty.Additionally, it also allows to set
endpointto override AWS API endpoint, because some AWS APIs requires you to override it. (e.g. Route53 ARC)Here's example code to define this new SFn task:
Description of how you validated changes
Added unit tests and integ tests.
Checklist
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license