diff --git a/changelog.md b/changelog.md index ec964bd..4877cbe 100644 --- a/changelog.md +++ b/changelog.md @@ -2,6 +2,11 @@ --- +## [11.0.3] 2026-01-19 + +- Queue now accepts `batchSize` and `batchWindow` properties; only works with `fifo true` +- Queue can now directly configure `fifo true|false` explicitly (default is `true`) + ## [11.0.0 - 11.0.1] 2025-11-28 - updated to >= node22 diff --git a/package.json b/package.json index 1c2a808..d6b7345 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,13 @@ { "name": "@architect/package", - "version": "11.0.1", + "version": "11.0.3", "description": "Package .arc for deployment with CloudFormation", "main": "src/index.js", "scripts": { "lint": "eslint . --fix", "test": "npm run lint && npm run coverage", "test:unit": "node --test 'test/unit/**/*-test.js'", + "test:integration": "node --test 'test/integration/**/*-test.js'", "coverage": "mkdir -p coverage && node --test --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=coverage/lcov.info --test-reporter=spec --test-reporter-destination=stdout 'test/unit/**/*-test.js'", "rc": "npm version prerelease --preid RC" }, @@ -20,13 +21,13 @@ "author": "Brian LeRoux ", "license": "Apache-2.0", "dependencies": { - "@architect/inventory": "~6.0.0", - "@architect/utils": "~6.0.0" + "@architect/inventory": "~6.1.0", + "@architect/utils": "~6.0.3" }, "devDependencies": { "@architect/eslint-config": "~3.0.0", "@aws-lite/client": "~0.23.2", "@aws-lite/s3": "~0.2.6", - "eslint": "~9.36.0" + "eslint": "~9.39.2" } } diff --git a/src/visitors/queues/index.js b/src/visitors/queues/index.js index 8a07108..bf15d48 100644 --- a/src/visitors/queues/index.js +++ b/src/visitors/queues/index.js @@ -9,8 +9,10 @@ module.exports = function visitQueues (inventory, template) { if (!inv.queues) return template inv.queues.forEach(queue => { - let { config } = queue - let { timeout, fifo } = config + let { config, batchSize, batchWindow, fifo } = queue + + // for backwards compat; if fifo isn't on the queue itself it could be within the config + if (!fifo) fifo = config.fifo let name = toLogicalID(queue.name) let queueLambda = `${name}QueueLambda` @@ -36,7 +38,7 @@ module.exports = function visitQueues (inventory, template) { template.Resources[queueQueue] = { Type: 'AWS::SQS::Queue', Properties: { - VisibilityTimeout: timeout, + VisibilityTimeout: config.timeout, }, } @@ -44,6 +46,16 @@ module.exports = function visitQueues (inventory, template) { if (fifo) { template.Resources[queueQueue].Properties.FifoQueue = fifo template.Resources[queueQueue].Properties.ContentBasedDeduplication = true + + template.Resources[queueLambda].Properties.ReservedConcurrentExecutions = batchSize || 1 + template.Resources[queueLambda].Properties.Events[queueEvent].Properties.BatchSize = 1 + template.Resources[queueLambda].Properties.Events[queueEvent].Properties.MaximumBatchingWindowInSeconds = 0 + + if (batchWindow) { + // When batchWindow is defined we adjust all the timeouts + template.Resources[queueQueue].Properties.VisibilityTimeout = batchWindow * 6 + template.Resources[queueLambda].Properties.Timeout = batchWindow + } } template.Outputs[`${name}SqsQueue`] = { diff --git a/test/integration/queue-test.js b/test/integration/queue-test.js new file mode 100644 index 0000000..b3c7d5a --- /dev/null +++ b/test/integration/queue-test.js @@ -0,0 +1,94 @@ +let { test } = require('node:test') +let { ok } = require('node:assert') + +let inventory = require('@architect/inventory') +let package = require('../../') + +test('Module is present', () => { + ok(package, 'Package module is present') +}) + +test('Can output plausible CloudFormation', async () => { + + let inv = await inventory({ + deployStage: 'staging', + rawArc: ` + @app + myapp + + @queues + test-q`, + }) + + let sam = package(inv) + + // Queue expected defaults + let timeout = sam.Resources.TestQQueueLambda.Properties.Timeout + ok(sam.Resources.TestQQueue.Properties.VisibilityTimeout === timeout) + ok(sam.Resources.TestQQueue.Properties.FifoQueue) + ok(sam.Resources.TestQQueue.Properties.ContentBasedDeduplication) + + // Queue Lambda expected defaults + ok(sam.Resources.TestQQueueLambda.Properties.ReservedConcurrentExecutions === 1) + ok(sam.Resources.TestQQueueLambda.Properties.Events.TestQQueueEvent.Properties.BatchSize === 1) + ok(sam.Resources.TestQQueueLambda.Properties.Events.TestQQueueEvent.Properties.MaximumBatchingWindowInSeconds === 0) +}) + +test('batchSize respected', async () => { + + let inv = await inventory({ + deployStage: 'staging', + rawArc: ` +@app +myapp +@queues +test-q + batchSize 5`, + }) + + let sam = package(inv) + + // Queue expected defaults + let timeout = sam.Resources.TestQQueueLambda.Properties.Timeout + ok(sam.Resources.TestQQueue.Properties.VisibilityTimeout === timeout) + ok(sam.Resources.TestQQueue.Properties.FifoQueue) + ok(sam.Resources.TestQQueue.Properties.ContentBasedDeduplication) + + // Queue Lambda expected defaults + ok(sam.Resources.TestQQueueLambda.Properties.ReservedConcurrentExecutions === 5) + ok(sam.Resources.TestQQueueLambda.Properties.Events.TestQQueueEvent.Properties.BatchSize === 1) + ok(sam.Resources.TestQQueueLambda.Properties.Events.TestQQueueEvent.Properties.MaximumBatchingWindowInSeconds === 0) + +}) + +test('batchWindow respected', async () => { + + let inv = await inventory({ + deployStage: 'staging', + rawArc: ` +@app +myapp +@queues +test-q + batchSize 5 + batchWindow 30`, + }) + + let sam = package(inv) + + let timeout = sam.Resources.TestQQueueLambda.Properties.Timeout + ok(timeout === 30) + + // Queue expected defaults + ok(sam.Resources.TestQQueue.Properties.VisibilityTimeout === timeout * 6) + ok(sam.Resources.TestQQueue.Properties.FifoQueue) + ok(sam.Resources.TestQQueue.Properties.ContentBasedDeduplication) + + // Queue Lambda expected defaults + ok(sam.Resources.TestQQueueLambda.Properties.ReservedConcurrentExecutions === 5) + ok(sam.Resources.TestQQueueLambda.Properties.Events.TestQQueueEvent.Properties.BatchSize === 1) + ok(sam.Resources.TestQQueueLambda.Properties.Events.TestQQueueEvent.Properties.MaximumBatchingWindowInSeconds === 0) + +}) + +// test deploy