-
What is the problem?During cdk synth (or cdk deploy) operation, stacks containing Nodejs lambdas compiled using ESBuild locally will fail to bundle, even if their parent Stack has a dependency explicitly stated. This error is non-descriptive, and states: Reproduction StepsCreate two stacks: Simple SQS queue stack: // /project/lib/queue-stack.ts
import * as cdk from "@aws-cdk/core";
import * as sqs from '@aws-cdk/aws-sqs';
// expressed in seconds
const DEFAULT_QUEUE_TIMEOUT = 60 * 5
interface QueueStackProps extends cdk.StackProps {
env?: cdk.Environment;
queueName: string;
queueTimeout?: cdk.Duration;
needsDLQ?: boolean;
}
export class BasicQueueStack extends cdk.Stack {
public readonly queue: sqs.Queue
public readonly queueURL: string
public readonly deadLetterQueue: sqs.Queue
constructor(scope: cdk.Construct, id: string, props: QueueStackProps) {
super(scope, id, props);
const { queueName, queueTimeout, needsDLQ } = props;
const queueVisibilityTimeout = queueTimeout || cdk.Duration.seconds(DEFAULT_QUEUE_TIMEOUT);
const queueConfig: any = {
queueName,
visibilityTimeout: queueVisibilityTimeout,
// deliveryDelay: cdk.Duration.seconds(15),
// retentionPeriod: cdk.Duration.seconds((4 * 24 * 60 * 60)) // default value is 345600 seconds (4 days)
}
// add in our Dead Letter Queue
if (needsDLQ) {
this.deadLetterQueue = new sqs.Queue(this, `${queueName}DLQ`, {
queueName: `DeadLetterQueue-${queueName}`
});
queueConfig.deadLetterQueue = {
queue: this.deadLetterQueue,
maxReceiveCount: 5
}
}
this.queue = new sqs.Queue(this, `${queueName}Queue`, queueConfig);
this.queueURL = this.queue.queueUrl.toString();
}
} Nodejs Lambda stack. // /project/lib/nodejs-lambda-stack.ts
import * as cdk from "@aws-cdk/core";
import * as lambda from '@aws-cdk/aws-lambda-nodejs'
interface NodejsLambdaStackProps extends cdk.StackProps {
env?: cdk.Environment;
functionName: string;
functionEntry: string;
functionProps: {[x:string]: any}
}
export class NodejsLambdaStack extends cdk.Stack {
public readonly lambda: lambda.NodejsFunction
constructor(scope: cdk.Construct, id: string, props: NodejsLambdaStackProps) {
super(scope, id, props);
const { functionName, functionEntry, functionProps: {timeout, memorySize, vpc, environmentVariables} } = props;
this.lambda = new lambda.NodejsFunction(this, `${functionName}Lambda`, {
entry: functionEntry, // accepts .js, .jsx, .ts and .tsx files
// handler: 'handler', // defaults to 'handler'
functionName,
bundling: {
// minify: true, // minify code, defaults to false
sourceMap: true,
define: { // Replace strings during build time
...environmentVariables
},
},
timeout,
memorySize, // default is 128 MB
vpc
});
}
} Reference both stacks in /bin, with Lambda Stack having SQS Queue Stack as a dependency: // /project/bin/stack.ts
import * as cdk from '@aws-cdk/core';
import { BasicQueueStack } from "../lib/queue-stack";
import { NodejsLambdaStack } from '../lib/nodejs-function-stack'
const app = new cdk.App();
const env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION };
const workflowName = `SomeWorkFlow`;
const queueStack = new BasicQueueStack(this, `${workflowName}QueueStack`, {
env,
queueName: workflowName,
needsDLQ: true
});
const {queue, queueURL} = queueStack;
const lambdaStack = new NodejsLambdaStack(this, `${workflowName}LambdaStack`, {
env,
functionName: `${workflowName}`,
functionEntry: path.join(__dirname, `/../lambda-fns/workflow/index.ts`),
functionProps: {
timeout: cdk.Duration.seconds(45),
memorySize: 256,
vpc,
environmentVariables: {
'process.env.AWS_QUEUE_URL': queueURL
}
}
})
lambdaStack.addDependency(queueStack); What did you expect to happen?Nodejs Lambda stack would:
What actually happened?
Actual error output:
CDK CLI Version$ cdk version 1.134.0 (build dd5e12d) Framework VersionNo response Node.js Versionnode -v v14.18.1 OSMacOS 11.6 LanguageTypescript Language Versiontsc -v Version 4.4.4 Other informationNo response |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 3 replies
-
Hi @spdolan What are you trying to achieve here exactly? The What you can do is pass the new lambda.NodejsFunction(this, 'MyFn', {
environment: {
QUEUE_URL: props.queueUrl,
}
}); Now you can use Also note that you don't need a const fn = new lambda.NodejsFunction(this, 'MyFn', {
environment: {
QUEUE_URL: props.queue.queueUrl,
}
});
queue.grantSendMessages(fn); Since the lambda stack references the queue from the queue stack you don't need to add a dependency between the stacks. |
Beta Was this translation helpful? Give feedback.
-
Thanks as always jogold 🙂 |
Beta Was this translation helpful? Give feedback.
-
Hello! Reopening this discussion to make it searchable. |
Beta Was this translation helpful? Give feedback.
Hi @spdolan
What are you trying to achieve here exactly?
The
queueUrl
is a deploy time value, it is only known after the queue stack is deployed. During synth it is represented by a token this is why you see${Token[TOKEN.209]}
. During synth/bundling those values are not resolved yet.What you can do is pass the
queueUrl
as a runtime environment variable to your Lambda function.Now you can use
process.env.QUEUE_URL
in your code and when the Lambda runs it will have the correct value.Also note that you don't need a
toString()
in your queue stack. And you can also pass thequeue
object betwee…