diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/sqs/integ.sqs-event-rule-target.js.snapshot/aws-cdk-sqs-event-target.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/sqs/integ.sqs-event-rule-target.js.snapshot/aws-cdk-sqs-event-target.template.json index 7bfa29e5df27d..f0070ef95e34f 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/sqs/integ.sqs-event-rule-target.js.snapshot/aws-cdk-sqs-event-target.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/sqs/integ.sqs-event-rule-target.js.snapshot/aws-cdk-sqs-event-target.template.json @@ -176,6 +176,74 @@ } ] } + }, + "StandardQueue4A8B3C4D": { + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "StandardQueuePolicyFB772D09": { + "Type": "AWS::SQS::QueuePolicy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl", + "sqs:SendMessage" + ], + "Condition": { + "ArnEquals": { + "aws:SourceArn": { + "Fn::GetAtt": [ + "StandardQueueRule2E5F2E91", + "Arn" + ] + } + } + }, + "Effect": "Allow", + "Principal": { + "Service": "events.amazonaws.com" + }, + "Resource": { + "Fn::GetAtt": [ + "StandardQueue4A8B3C4D", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "Queues": [ + { + "Ref": "StandardQueue4A8B3C4D" + } + ] + } + }, + "StandardQueueRule2E5F2E91": { + "Type": "AWS::Events::Rule", + "Properties": { + "ScheduleExpression": "rate(1 minute)", + "State": "ENABLED", + "Targets": [ + { + "Arn": { + "Fn::GetAtt": [ + "StandardQueue4A8B3C4D", + "Arn" + ] + }, + "Id": "Target0", + "SqsParameters": { + "MessageGroupId": "MyMessageGroupId" + } + } + ] + } } }, "Parameters": { @@ -212,4 +280,4 @@ ] } } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/sqs/integ.sqs-event-rule-target.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/sqs/integ.sqs-event-rule-target.ts index 876e6afc4130a..42a9900ed6aa4 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/sqs/integ.sqs-event-rule-target.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/sqs/integ.sqs-event-rule-target.ts @@ -30,4 +30,15 @@ event.addTarget(new targets.SqsQueue(queue, { deadLetterQueue, })); +// Test messageGroupId support for standard (non-FIFO) queues +const standardQueue = new sqs.Queue(stack, 'StandardQueue'); + +const standardQueueEvent = new events.Rule(stack, 'StandardQueueRule', { + schedule: events.Schedule.rate(cdk.Duration.minutes(1)), +}); + +standardQueueEvent.addTarget(new targets.SqsQueue(standardQueue, { + messageGroupId: 'MyMessageGroupId', +})); + app.synth(); diff --git a/packages/aws-cdk-lib/aws-events-targets/README.md b/packages/aws-cdk-lib/aws-events-targets/README.md index 3cad3a29eff77..8f1ea5a235ed9 100644 --- a/packages/aws-cdk-lib/aws-events-targets/README.md +++ b/packages/aws-cdk-lib/aws-events-targets/README.md @@ -718,6 +718,56 @@ rule.addTarget(new targets.RedshiftQuery(workgroup.attrWorkgroupWorkgroupArn, { })); ``` +## Send events to an SQS queue + +Use the `SqsQueue` target to send events to an SQS queue. + +The code snippet below creates an event rule that sends events to an SQS queue every hour: + +```ts +import * as sqs from 'aws-cdk-lib/aws-sqs'; + +const queue = new sqs.Queue(this, 'MyQueue'); + +const rule = new events.Rule(this, 'Rule', { + schedule: events.Schedule.rate(cdk.Duration.hours(1)), +}); + +rule.addTarget(new targets.SqsQueue(queue)); +``` + +### Using Message Group IDs + +You can specify a `messageGroupId` to ensure messages are processed in order. This parameter is required for FIFO queues and optional for standard queues: + +```ts +import * as sqs from 'aws-cdk-lib/aws-sqs'; + +// FIFO queue - messageGroupId required +const fifoQueue = new sqs.Queue(this, 'MyFifoQueue', { + fifo: true, +}); + +const fifoRule = new events.Rule(this, 'FifoRule', { + schedule: events.Schedule.rate(cdk.Duration.hours(1)), +}); + +fifoRule.addTarget(new targets.SqsQueue(fifoQueue, { + messageGroupId: 'MyMessageGroupId', +})); + +// Standard queue - messageGroupId optional (SQS Fair queue feature) +const standardQueue = new sqs.Queue(this, 'MyStandardQueue'); + +const standardRule = new events.Rule(this, 'StandardRule', { + schedule: events.Schedule.rate(cdk.Duration.hours(1)), +}); + +standardRule.addTarget(new targets.SqsQueue(standardQueue, { + messageGroupId: 'MyMessageGroupId', // Optional for standard queues +})); +``` + ## Publish to an SNS Topic Use the `SnsTopic` target to publish to an SNS Topic. diff --git a/packages/aws-cdk-lib/aws-events-targets/lib/sqs.ts b/packages/aws-cdk-lib/aws-events-targets/lib/sqs.ts index 52fe035e79320..f5f01ef3d361d 100644 --- a/packages/aws-cdk-lib/aws-events-targets/lib/sqs.ts +++ b/packages/aws-cdk-lib/aws-events-targets/lib/sqs.ts @@ -2,7 +2,7 @@ import { addToDeadLetterQueueResourcePolicy, TargetBaseProps, bindBaseTargetConf import * as events from '../../aws-events'; import * as iam from '../../aws-iam'; import * as sqs from '../../aws-sqs'; -import { FeatureFlags, ValidationError } from '../../core'; +import { FeatureFlags } from '../../core'; import * as cxapi from '../../cx-api'; /** @@ -13,9 +13,10 @@ export interface SqsQueueProps extends TargetBaseProps { /** * Message Group ID for messages sent to this queue * - * Required for FIFO queues, leave empty for regular queues. + * Required for FIFO queues. For standard queues, this parameter is optional + * and can be used for SQS fair queue feature and deduplication. * - * @default - no message group ID (regular queue) + * @default - no message group ID */ readonly messageGroupId?: string; @@ -41,9 +42,7 @@ export interface SqsQueueProps extends TargetBaseProps { */ export class SqsQueue implements events.IRuleTarget { constructor(public readonly queue: sqs.IQueue, private readonly props: SqsQueueProps = {}) { - if (props.messageGroupId !== undefined && !queue.fifo) { - throw new ValidationError('messageGroupId cannot be specified for non-FIFO queues', queue); - } + // messageGroupId is now supported for both FIFO and standard SQS queues } /** diff --git a/packages/aws-cdk-lib/aws-events-targets/test/sqs/sqs.test.ts b/packages/aws-cdk-lib/aws-events-targets/test/sqs/sqs.test.ts index 4bdd8f633e6a5..25e1f1c381e43 100644 --- a/packages/aws-cdk-lib/aws-events-targets/test/sqs/sqs.test.ts +++ b/packages/aws-cdk-lib/aws-events-targets/test/sqs/sqs.test.ts @@ -259,12 +259,37 @@ test('Encrypted queues result in a permissive policy statement when the feature }); }); -test('fail if messageGroupId is specified on non-fifo queues', () => { +test('messageGroupId is supported for standard (non-FIFO) queues', () => { const stack = new Stack(); const queue = new sqs.Queue(stack, 'MyQueue'); + const rule = new events.Rule(stack, 'MyRule', { + schedule: events.Schedule.rate(Duration.hours(1)), + }); + + // WHEN + rule.addTarget(new targets.SqsQueue(queue, { + messageGroupId: 'MyMessageGroupId', + })); - expect(() => new targets.SqsQueue(queue, { messageGroupId: 'MyMessageGroupId' })) - .toThrow(/messageGroupId cannot be specified/); + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { + ScheduleExpression: 'rate(1 hour)', + State: 'ENABLED', + Targets: [ + { + Arn: { + 'Fn::GetAtt': [ + 'MyQueueE6CA6235', + 'Arn', + ], + }, + Id: 'Target0', + SqsParameters: { + MessageGroupId: 'MyMessageGroupId', + }, + }, + ], + }); }); test('fifo queues are synthesized correctly', () => {