diff --git a/packages/serverless-offline-sqs/README.md b/packages/serverless-offline-sqs/README.md index 52aff3ab..42f4398e 100644 --- a/packages/serverless-offline-sqs/README.md +++ b/packages/serverless-offline-sqs/README.md @@ -74,6 +74,12 @@ resources: Type: AWS::SQS::Queue Properties: QueueName: MyFourthQueue + RedrivePolicy: + deadLetterTargetArn: # Support only this format for autoCreate + Fn::GetAtt: + - MyFourthQueueDlq + - Arn + maxReceiveCount: 6 MyFifthQueue: # Support for Fifo queue creation starts from 3.1 only Type: AWS::SQS::Queue @@ -81,6 +87,11 @@ resources: QueueName: MyFifthQueue.fifo FifoQueue: true ContentBasedDeduplication: true + + MyFourthQueueDlq: + Type: AWS::SQS::Queue + Properties: + QueueName: MyFourthQueueDlq ``` ### SQS diff --git a/packages/serverless-offline-sqs/src/index.js b/packages/serverless-offline-sqs/src/index.js index 1e1ff7d4..c7c03c6d 100644 --- a/packages/serverless-offline-sqs/src/index.js +++ b/packages/serverless-offline-sqs/src/index.js @@ -130,6 +130,8 @@ class ServerlessOfflineSQS { this.sqs = new SQS(this.lambda, resources, this.options); + await this.sqs.createDlq(get(['service', 'resources', 'Resources'], this.serverless)); + await this.sqs.create(events); if (!skipStart) { diff --git a/packages/serverless-offline-sqs/src/sqs.js b/packages/serverless-offline-sqs/src/sqs.js index 6bd9b347..fba4b862 100644 --- a/packages/serverless-offline-sqs/src/sqs.js +++ b/packages/serverless-offline-sqs/src/sqs.js @@ -1,7 +1,18 @@ const {default: PQueue} = require('p-queue'); const SQSClient = require('aws-sdk/clients/sqs'); -// eslint-disable-next-line no-shadow -const {pipe, get, values, matches, find, mapValues, isPlainObject, toString} = require('lodash/fp'); +const { + pipe, + get, + values, + matches, + find, + mapValues, + isPlainObject, + // eslint-disable-next-line no-shadow + toString, + map, + compact +} = require('lodash/fp'); const {logWarning} = require('serverless-offline/dist/serverlessLog'); const SQSEventDefinition = require('./sqs-event-definition'); const SQSEvent = require('./sqs-event'); @@ -30,6 +41,10 @@ class SQS { return Promise.all(events.map(({functionKey, sqs}) => this._create(functionKey, sqs))); } + createDlq(resources) { + return this._createDlq(resources); + } + start() { this.queue.start(); } @@ -48,6 +63,33 @@ class SQS { return this._sqsEvent(functionKey, sqsEvent); } + _createDlq(resources) { + if (!this.options.autoCreate) return; + const dlqNames = this._getDlqNames(resources); + return Promise.all( + dlqNames.map(queueName => { + return this._createQueue({queueName}); + }) + ); + } + + // eslint-disable-next-line class-methods-use-this + _getDlqNames(resources) { + return pipe( + values, + map(value => { + const dlq = get(['Properties', 'RedrivePolicy', 'deadLetterTargetArn'], value); + if (!dlq) return; + const [resourceName, attribute] = dlq['Fn::GetAtt']; + const type = get(['Type'], resources[resourceName]); + if (attribute !== 'Arn') return; + if (type !== 'AWS::SQS::Queue') return; + return get(['Properties', 'QueueName'], resources[resourceName]); + }), + compact + )(resources); + } + async _getQueueUrl(queueName) { try { return await this.client.getQueueUrl({QueueName: queueName}).promise();