Closed gabor-s closed 4 years ago
It won't solve any other pains that are outlined above, but if you are genuinely blocked on async (ha) and only need it at the top stack level, I'd encourage checking out SST. It's a meta framework built on top of the CDK that, amongst other things, supports async in Stack declarations.
Just want to add here that I stumbled across this thread and was pretty disheartened about it as well. However, upon looking at the aws-quickstart-blueprints library for typescript, there is a pattern for async await through the cdk by nature of the fact that node will wait until all promises have resolved.
While this isn't free, creating an underlying resource stack and then keeping a list of ordered calls to subsequent addons is a pattern that will chain async behaviors. This definitely has some edges to it, but allows for things like fetching an existing secret and running bcrypt on it for a kubernetes secret that is created for argocd.
It would be nice to create a further abstraction of this current library that does not specifically target EKS cluster's but it can be cannabalized to basically be a build method that calls X number of "AddOn" interfaces that have an async deploy/postDeploy method in successive order after creating the underlying resource.
The only place I can see this being problematic would be if a resource is late created in one of these methods and immediately accessed in another constructor (so it is not without teeth, but I believe I can make this edge case go away for usage of custom_resources).
Would love to see this more readily supported by the base framework though
@eladb
The IP allow list above is a good example - performing an HTTP request during synthesis means that build output can change without any change to the source, but commiting a JSON file to your source control is a reasonable way to avoid this and get all the benefits of a deterministic build. The async constraint was the reason we even had that conversation :-)
In my case, I need to create a CloudFront PublicKey, so I have a script to create/rotate public/private key contents, and some metadata (createdAt), and save it to a System's Manager parameter. Then save the parameter name in cdk.context.json.
At synth time I need to retrieve the public key contents to create the PublicKey, so I'm forced to do an async call to the AWS SSM API...
I don't think saving key contents to source control is a good practice 😅
Workaround using Lazy to resolve the value from a immediately invoked async function:
import { StringParameter } from 'aws-cdk-lib/aws-ssm';
import { Lazy, Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { ECRClient, DescribeImagesCommand } from '@aws-sdk/client-ecr'
export class AsyncInConstructStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
let digest: string = "not set";
(async () => {
const ecrClient = new ECRClient({ region: "us-east-1" })
const result = await ecrClient.send(new DescribeImagesCommand({
repositoryName: "my-repo",
imageIds: [{imageTag: "latest"}]
}))
digest = result.imageDetails![0].imageDigest!
})()
new StringParameter(this, 'parameter', {
stringValue: Lazy.string({ produce: () => digest }),
})
}
}
Synth Output:
Resources:
parameter76C24FC7:
Type: AWS::SSM::Parameter
Properties:
Type: String
Value: sha256:a8cc10cabc4278563c1a915a226db413dc0ec2c064d325d653435b20b08f4872
Metadata:
aws:cdk:path: AsyncInConstructStack/parameter/Resource
@deuscapturus Wouldn't that solution result in race conditions leading to possible random failures?
To test this, if you put a delay in the async function, does it still work? e.g.
await new Promise((resolve) => setTimeout(resolve, 30000)); // 30 second delay to simulate slow API
digest = ...
@deuscapturus Wouldn't that solution result in race conditions leading to possible random failures?
To test this, if you put a delay in the async function, does it still work? e.g.
await new Promise((resolve) => setTimeout(resolve, 30000)); // 30 second delay to simulate slow API digest = ...
I tested for race conditions before posting.
The explanation of non deterministic doesn't make sense at all because it only applies to nodejs nature of async operations, in Java cdk one could consult a database or make an http call and proceed with the cdk based on that response because Java will do that in "sync" way. The real issue is that the code architecture to use class constructors to build your infrastructure is non sense (this is the real anti pattern here), and in nodejs you cannot have async class instantiation.
@eladb open this ticket up, please This is ridiculous
Most people's views are against your view
How do you use the same/current credentials of cdk into sdk when creating an instance from a class?
e.x.
.
.
const sdk_apigw = new sdk.APIGateway({credentials: xxx});`
:question: General Issue
The Question
Is it possible to do asynchronous processing in a Construct? Is there anything in CDK that will wait for a promise to resolve? It seems that everything is synchronous.
I need to resolve a string value to a path, but it could take some time so implemented it asynchronously.
Options considered:
Aspects
The visit method is synchronous.
Tokens
The resolve method is synchronous.
Create the app asynchronously
Context
The same as before, but put result into the context, so don't have to pass it to every stack/construct. Honestly, I don't really like this solution, because the construct is reaching out to some known location to get a value. Like
process.env
calls that are scattered throughout the code.Is there any support in CDK for asynchronous processing? Or is it an anti-pattern and I'm doing the wrong way?
Environment
Other information