feat(ecs-service-extensions): Subscribe Extension#16049
feat(ecs-service-extensions): Subscribe Extension#16049mergify[bot] merged 9 commits intoaws:masterfrom
Conversation
nathanpeck
left a comment
There was a problem hiding this comment.
Looks good overall! I requested a few minor changes. I assume there is another paired Topic extension that needs to go with this, in another PR?
packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/subscribe.ts
Outdated
Show resolved
Hide resolved
| * The created subscriptions can be accessed using `subscriptions` field and the | ||
| * default queue for this service can be accessed using the getter `<extension>.eventsQueue`. | ||
| */ | ||
| export class SubscribeExtension extends ServiceExtension { |
There was a problem hiding this comment.
The name of the extension doesn't feel quite right. The naming methodology of CDK favors having nouns for the classes, and then verb methods on those classes. And I think in general we've tried to keep the same methodology for the extensions too. So it should be something like "service.add(noun)"
I'd suggest something like "Service.add(new IncomingQueue())" or something like that. You may have a better name idea as well, but think of nouns and adjectives for the name, rather than verbs.
There was a problem hiding this comment.
Updated the extension name to EventsQueue(), I felt we are already creating a default queue with name eventsQueue for the service so it would be more intuitive to name the extension the same. Let me know if that sounds good!
| } | ||
| } | ||
|
|
||
| private createQueues(name: string, queueProps?: sqs.QueueProps, deadLetterQueueProps?: DeadLetterQueueProps) : sqs.IQueue { |
There was a problem hiding this comment.
It might be possible that some folks will not want a dead letter queue. For example if a queue has highly valuable messages going to it, and a message is failing to be processed, they may want to leave it on the queue and fix the code of their queue consuming service, rather than rejecting the message to a dead letter queue. We should make sure dead letter queue is optional
| return { | ||
| ...props, | ||
|
|
||
| environment: { ...(props.environment || {}), ...this.environment }, |
There was a problem hiding this comment.
That's a cool one liner!
packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/subscribe.ts
Outdated
Show resolved
Hide resolved
packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/subscribe.ts
Outdated
Show resolved
Hide resolved
| advanced features. Here are some useful extensions that we have reviewed: | ||
|
|
||
| - [ListenerRulesExtension](https://www.npmjs.com/package/@wheatstalk/ecs-service-extension-listener-rules) for more precise control over Application Load Balancer rules | ||
| - SubscribeExtension to allow the service to create SQS Queues to subscribe and consume messages published to SNS Topics |
There was a problem hiding this comment.
Do we need to add more docs so that users can at least have some example showing them how to use this feature?
There was a problem hiding this comment.
Updated the docs with more guidance on using the extension. Will add a full example once the publish part is over.
packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/subscribe.ts
Outdated
Show resolved
Hide resolved
packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/subscribe.ts
Outdated
Show resolved
Hide resolved
| * | ||
| * @default none | ||
| */ | ||
| readonly eventsDeadLetterQueueProps?: DeadLetterQueueProps; |
There was a problem hiding this comment.
I don't get why we need this field. Can't they just specify dead letter queue within eventsQueueProps?
There was a problem hiding this comment.
We decided to drop the queue and dead letter queue props completely as they were only being used to instantiate the SQS Queue and served no other purpose. So now if the user doesn't want a queue to be created with the set defaults they need to provide a custom queue as an input prop. This seems to largely simplify the experience as well.
Do let me know if that makes sense or if you have any suggestions!
packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/subscribe.ts
Outdated
Show resolved
Hide resolved
packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/subscribe.ts
Outdated
Show resolved
Hide resolved
| * | ||
| * @default none | ||
| */ | ||
| readonly eventsQueueProps?: sqs.QueueProps; |
There was a problem hiding this comment.
Is it possible to default to eventsQueueProps and make assumptions for the customer if they don't want to customize?
There was a problem hiding this comment.
How does this sound? The defaults will be the one's set by CF.
| } else { | ||
| this._eventsQueue = this.createQueues('Events', this.props?.eventsQueueProps, this.props?.eventsDeadLetterQueueProps); | ||
| } | ||
| this.environment[`${this.parentService.id.toUpperCase()}_EVENTS_QUEUE_URL`] = this._eventsQueue.queueUrl; |
There was a problem hiding this comment.
Can we standardize these variable names with Copilot?
For example, we'll use
COPILOT_QUEUE_URI for the primary queue
COPILOT_TOPIC_QUEUE_URIS for a JSON map: {"service-topic": "https://queue-uri.amazonaws.com"}
COPILOT_SNS_TOPIC_ARNS
Could we do something similar and swap COPILOT for ${PARENTSERVICE}?
There was a problem hiding this comment.
Actually, the environment in CDK is typed in to be a set of key-value pairs of strings. That sort of limits our ability to add the variables exactly like that.
There was a problem hiding this comment.
Update: As the topic-specific queues will be user input, we will be removing the addition of these queueURLs as environment variables. The only queue possibly created by us is the default eventsQueue, and that URL will still be added to the environment.
packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/subscribe.ts
Outdated
Show resolved
Hide resolved
Pull request has been modified.
Yes, working on it next! |
packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/events-queue.ts
Outdated
Show resolved
Hide resolved
packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/events-queue.ts
Outdated
Show resolved
Hide resolved
efekarakus
left a comment
There was a problem hiding this comment.
Looks great! Mostly a recommendation around adding a new interface so that we can augment the extension with other types of subscriptions.
| const topicSubscription = { | ||
| topic: new sns.Topic(stack, 'my-topic'), | ||
| }; | ||
|
|
||
| const myServiceDescription = nameDescription.add(new EventsQueue({ | ||
| // Provide a custom queue for the service. If a queue is not provided, a default queue is created for the service | ||
| eventsQueue: myCustomQueue, | ||
| // Provide list of topics the you want the `eventsQueue` to subscribe to | ||
| topicSubscriptions: [topicSubscription], | ||
| })); |
There was a problem hiding this comment.
nit: to illustrate how simple it is to get started, what do you think of updating the first example to:
const myServiceDescription = nameDescription.add(new EventsQueue({
// Provide list of topics the you want the `eventsQueue` to subscribe to
topicSubscriptions: [{
topic: new sns.Topic(stack, 'my-topic'),
}],
}));| * | ||
| * @default none | ||
| */ | ||
| readonly topicSubscriptions?: TopicSubscriptionProps[]; |
There was a problem hiding this comment.
My typescript foo is weak 😅 since we want to have at least one subscription would it make a different to have the following?
| readonly topicSubscriptions?: TopicSubscriptionProps[]; | |
| readonly topicSubscriptions: TopicSubscriptionProps[]; |
There was a problem hiding this comment.
I wonder if we can make this even more generic for the future so that it's not only topic subscriptions that we accept but also eventbus subscriptions.
We could create a Susbcribable interface that a TopicSubscription class implements, here is a bad skeleton 😛 : https://gist.github.com/efekarakus/78567b5f4aff33434963dc42080be541
There was a problem hiding this comment.
since we want to have at least one subscription would it make a different to have the following?
As this extension is an ‘extension’ 😛 of the current queue processing service (which allows the user to set up a queue and DLQ for their service), I feel we should also support the case where no subscriptions are provided. But if we don’t want to do that then this change would be necessary.
packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/events-queue.ts
Outdated
Show resolved
Hide resolved
packages/@aws-cdk-containers/ecs-service-extensions/lib/extensions/events-queue.ts
Outdated
Show resolved
Hide resolved
efekarakus
left a comment
There was a problem hiding this comment.
Looks good! one more refactor request and then we can ![]()
| public subscribe(queue: sqs.IQueue) : sqs.IQueue | undefined { | ||
| if (this.queue) { | ||
| this.topic.addSubscription(new subscription.SqsSubscription(this.queue)); | ||
| } else { | ||
| this.topic.addSubscription(new subscription.SqsSubscription(queue)); | ||
| } | ||
| return this.queue; | ||
| } |
There was a problem hiding this comment.
From our discussion, what do you think of having subscribe instead take as input a QueueExtension?
public subscribe(extension: QueueExtension) {
let queue = extension.eventsQueue();
if (this.queue) {
queue = this.queue;
}
this.topic.addSubscription(new subscription.SqsSubscription(queue));
}This way, I think the interface becomes a bit clearer. If a TopicSubscription has a queue then we will use it, otherwise it will be the eventsQueue.
| const subsQueue = subs.subscribe(this._eventsQueue); | ||
| if (subsQueue) { | ||
| this.subscriptionQueues.push(subsQueue); | ||
| } |
There was a problem hiding this comment.
and this would become:
| const subsQueue = subs.subscribe(this._eventsQueue); | |
| if (subsQueue) { | |
| this.subscriptionQueues.push(subsQueue); | |
| } | |
| sub.subscribe(this); | |
| if (sub.queue) { | |
| this.subscriptionQueues.push(sub.queue); | |
| } |
There was a problem hiding this comment.
The variable subs is of the type ISubscribable so we first need to do a type check before we can access it’s queue, something like this:
if (subs instanceof TopicSubscription) {
if (subs.queue) {
this.subscriptionQueues.push(subs.queue);
}
}So it was either the type-check here or dealing with a return in the subscribe method. I feel your suggestion makes the interface look neater, I just wanted to confirm if the type-check was a concern.
|
Thank you for contributing! Your pull request will be updated from master and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork). |
AWS CodeBuild CI Report
Powered by github-codebuild-logs, available on the AWS Serverless Application Repository |
|
Thank you for contributing! Your pull request will be updated from master and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork). |
---- This PR adds a new service extension, `SubscribeExtension`. This extension can be added to a service to create SQS Queues which can subscribe to the SNS Topics provided by the user. It creates a default SQS Queue called `eventsQueue` . It also supports creation of topic-specific queues and sets up the SNS subscriptions accordingly. The created topic-queue subscriptions can be accessed using `subscriptions` field of the extension and the default queue for this service can be accessed using the `eventsQueue` getter method. (This PR does not include autoscaling, will be adding it in a separate PR) *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
---- This PR adds a new service extension, `SubscribeExtension`. This extension can be added to a service to create SQS Queues which can subscribe to the SNS Topics provided by the user. It creates a default SQS Queue called `eventsQueue` . It also supports creation of topic-specific queues and sets up the SNS subscriptions accordingly. The created topic-queue subscriptions can be accessed using `subscriptions` field of the extension and the default queue for this service can be accessed using the `eventsQueue` getter method. (This PR does not include autoscaling, will be adding it in a separate PR) *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
---- This PR adds a new service extension, `SubscribeExtension`. This extension can be added to a service to create SQS Queues which can subscribe to the SNS Topics provided by the user. It creates a default SQS Queue called `eventsQueue` . It also supports creation of topic-specific queues and sets up the SNS subscriptions accordingly. The created topic-queue subscriptions can be accessed using `subscriptions` field of the extension and the default queue for this service can be accessed using the `eventsQueue` getter method. (This PR does not include autoscaling, will be adding it in a separate PR) *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
---- This PR adds a new service extension, `PublisherExtension`. This extension can be added to a service to allow it to publish events to SNS Topics. (This PR when paired with #16049 can be used to set up the pub/ sub architecture pattern) It sets up publish permissions for the service to be able to publish events to the topics provided. The user can also provide a list of accounts that will be given permissions to subscribe to the given topics. *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
This PR adds a new service extension,
SubscribeExtension. This extension can be added to a service to create SQS Queues which can subscribe to the SNS Topics provided by the user.It creates a default SQS Queue called
eventsQueue. It also supports creation of topic-specific queues and sets up the SNS subscriptions accordingly. The created topic-queue subscriptions can be accessed usingsubscriptionsfield of the extension and the default queue for this service can be accessed using theeventsQueuegetter method. (This PR does not include autoscaling, will be adding it in a separate PR)By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license