internal TheScalableWebhookStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props) { /* * DynamoDB Table * This is standing in for what is RDS on the diagram due to simpler/cheaper setup */ _dynamoDbTable = new DynamoDB.Table(this, "Messages", new DynamoDB.TableProps { PartitionKey = new DynamoDB.Attribute { Name = "id", Type = DynamoDB.AttributeType.STRING } }); /* * Queue Setup */ _queueRds = new SQS.Queue(this, "RDSPublishQueue", new SQS.QueueProps { VisibilityTimeout = Duration.Seconds(300) }); /* * Lambdas * Both publisher and subscriber from pattern */ /* * defines an AWS Lambda resource to publish to our sqs_queue */ _functionPublish = new Lambda.Function(this, "SQSPublishLambdaHandler", new Lambda.FunctionProps { Runtime = Lambda.Runtime.NODEJS_12_X, // execution environment Handler = "lambda.handler", // file is "lambda", function is "handler" Code = Lambda.Code.FromAsset("lambda_fns/publish"), // code loaded from the "lambda_fns/publish" directory Environment = new Dictionary <string, string> { { "queueURL", _queueRds.QueueUrl } } }); _queueRds.GrantSendMessages(_functionPublish); /* * defines an AWS Lambda resource to pull from our sqs_queue */ _functionSubscribe = new Lambda.Function(this, "SQSSubscribeLambdaHandler", new Lambda.FunctionProps { Runtime = Lambda.Runtime.NODEJS_12_X, // execution environment Handler = "lambda.handler", // file is "lambda", function is "handler" Code = Lambda.Code.FromAsset("lambda_fns/subscribe"), // code loaded from the "lambda_fns/subscribe" directory Environment = new Dictionary <string, string> { { "queueURL", _queueRds.QueueUrl }, { "tableName", _dynamoDbTable.TableName } }, ReservedConcurrentExecutions = 2 // throttle lambda to 2 concurrent invocations }); _queueRds.GrantConsumeMessages(_functionSubscribe); _functionSubscribe.AddEventSource(new LambdaEvents.SqsEventSource(_queueRds)); _dynamoDbTable.GrantReadWriteData(_functionSubscribe); /** * API Gateway Proxy * Used to expose the webhook through a URL * * defines an API Gateway REST API resource backed by our "sqs_publish_lambda" function. */ new APIG.LambdaRestApi(this, "Endpoint", new APIG.LambdaRestApiProps { Handler = _functionPublish }); }
internal TheStateMachineStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props) { // Step Function Starts Here // The first thing we need to do is see if they are asking for pineapple on a pizza _pineppaleCheckHandler = new Lambda.Function(this, "pineappleCheckLambdaHandler", new Lambda.FunctionProps { Runtime = Lambda.Runtime.NODEJS_12_X, Code = Lambda.Code.FromAsset("lambda_fns"), Handler = "orderPizza.handler" }); /* * Step functions are built up of steps, we need to define our first step * This step was refactored due to Deprecated function */ _orderPizzaTask = new StepFuncionTasks.LambdaInvoke(this, "Order Pizza Job", new StepFuncionTasks.LambdaInvokeProps { LambdaFunction = _pineppaleCheckHandler, InputPath = "$.flavour", ResultPath = "$.pineappleAnalysis", PayloadResponseOnly = true }); // Pizza Order failure step defined _jobFailed = new StepFunction.Fail(this, "Sorry, We Dont add Pineapple", new StepFunction.FailProps { Cause = "Failed To Make Pizza", Error = "They asked for Pineapple" }); // If they didnt ask for pineapple let's cook the pizza _cookPizza = new StepFunction.Pass(this, "Lets make your pizza"); // If they ask for a pizza with pineapple, fail. Otherwise cook the pizza _chainDefinition = StepFunction.Chain .Start(_orderPizzaTask) .Next(new StepFunction.Choice(this, "With Pineapple?") // Logical choice added to flow .When(StepFunction.Condition.BooleanEquals("$.pineappleAnalysis.containsPineapple", true), _jobFailed) .Otherwise(_cookPizza)); // Building the state machine _stateMachine = new StepFunction.StateMachine(this, "StateMachine", new StepFunction.StateMachineProps { Definition = _chainDefinition, Timeout = Duration.Minutes(5) }); /** * Dead Letter Queue Setup * SQS creation * https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-dead-letter-queues.html */ _deadeLetterQueue = new SQS.Queue(this, "stateMachineLambdaDLQ", new SQS.QueueProps { VisibilityTimeout = Duration.Seconds(300) }); // defines an AWS Lambda resource to connect to our API Gateway _stateMachineHandler = new Lambda.Function(this, "stateMachineLambdaHandler", new Lambda.FunctionProps { Runtime = Lambda.Runtime.NODEJS_12_X, Code = Lambda.Code.FromAsset("lambda_fns"), Handler = "stateMachineLambda.handler", DeadLetterQueue = _deadeLetterQueue, Environment = new Dictionary <string, string> { { "statemachine_arn", _stateMachine.StateMachineArn } } }); // Grants to state machine execution _stateMachine.GrantStartExecution(_stateMachineHandler); /* * Simple API Gateway proxy integration */ // defines an API Gateway REST API resource backed by our "sqs_publish_lambda" function. new APIGateway.LambdaRestApi(this, "Endpoint", new APIGateway.LambdaRestApiProps { Handler = _stateMachineHandler }); }