Skip to content

Commit

Permalink
Design proposal for Queue Worker Service
Browse files Browse the repository at this point in the history
  • Loading branch information
piradeepk committed May 2, 2019
1 parent ed39a8c commit 3654a48
Showing 1 changed file with 225 additions and 0 deletions.
225 changes: 225 additions & 0 deletions design/aws-ecs-autoscaling-queue-worker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
# AWS ECS - L3 Construct for Autoscaling ECS/Fargate Service that Processes Items in a SQS Queue

To address issue [#2396](https://github.com/awslabs/aws-cdk/issues/2396), the AWS ECS CDK construct library should provide a way for customers to create a queue worker service (an AWS ECS/Fargate service that processes items from an sqs queue). This would mean adding new ECS CDK constructs `Ec2QueueWorkerService` and `FargateQueryWorkerService`, that would take in the necessary properties required to create a task definition, an SQS queue as well as an ECS/Fargate service and enable autoscaling for the service based on cpu usage and the SQS queue's approximateNumberOfMessagesVisible metric.

## General approach

The new `ecs.QueueWorkerServiceBase`, `ecs.Ec2QueueWorkerService` and `ecs.FargateQueueWorkerService` classes will create L3 constructs for:

* Ec2QueueWorkerService
* FargateQueueWorkerService

A `QueueWorkerService` will create a task definition with the specified container (on both EC2 and Fargate). An AWS SQS `Queue` will be created and autoscaling of the ECS Service will be dependent on both CPU as well as the SQS queue's `ApproximateNumberOfMessagesVisible` metric.

The `QueueWorkerService` constructs (for EC2 and Fargate) will use the following existing constructs:

* Ec2TaskDefinition/FargateTaskDefinition - To create a Task Definition for the container to start
* SQSQueue - The queue that the worker is processing from
* Ec2Service/FargateService - The Service running the container

## Code changes

Given the above, we should make the following changes to support queue workers on ECS (for both EC2 and Fargate):
1. Create `QueueWorkerServiceBaseProps` interface and `QueueWorkerServiceBase` construct
2. Create `Ec2QueueWorkerServiceProps` interface and `Ec2QueueWorkerService` construct
3. Create `FargateQueueWorkerServiceProps` interface and `FargateQueueWorkerService` construct

### Part 1: Create `QueueWorkerServiceBaseProps` interface and `QueueWorkerServiceBase` construct

The `QueueWorkerServiceBaseProps` interface will contain common properties used to construct both the Ec2QueueWorkerService and the FargateQueueWorkerService:

```ts
/**
* Properties to define an Query Worker service
*/
export interface QueueWorkerServiceBaseProps {
/**
* Cluster where service will be deployed
*/
readonly cluster: ICluster;

/**
* The image to start.
*/
readonly image: ContainerImage;

/**
* The CMD value to pass to the container. A string with commands delimited by commas.
*
* @default none
*/
readonly command?: string;

/**
* Number of desired copies of running tasks
*
* @default 1
*/
readonly desiredTaskCount?: number;

/**
* Flag to indicate whether to enable logging
*
* @default true
*/
readonly enableLogging?: boolean;

/**
* The environment variables to pass to the container.
*
* @default none
*/
readonly environment?: { [key: string]: string };

/**
* A name for the queue.
*
* If specified and this is a FIFO queue, must end in the string '.fifo'.
*
* @default CloudFormation-generated name
*/
readonly queueName?: string;

/**
* Maximum capacity to scale to.
*
* @default (desiredTaskCount * 2)
*/
readonly maxScalingCapacity?: number

/**
* The intervals for scaling based on the SQS queue's ApproximateNumberOfMessagesVisible metric.
*
* Maps a range of metric values to a particular scaling behavior.
* https://docs.aws.amazon.com/autoscaling/ec2/userguide/as-scaling-simple-step.html
*
* @default [{ upper: 0, change: -1 },{ lower: 100, change: +1 },{ lower: 500, change: +5 }]
*/
readonly scalingSteps: autoScaling.ScalingInterval[];
}
```

### Part 2: Create `Ec2QueueWorkerServiceProps` interface and `Ec2QueueWorkerService` construct

The `Ec2QueueWorkerServiceProps` interface will contain properties to construct the Ec2TaskDefinition, SQSQueue and Ec2Service:

```ts
/**
* Properties to define an ECS service
*/
export interface Ec2QueueWorkerServiceProps {
/**
* The minimum number of CPU units to reserve for the container.
*
* @default none
*/
readonly cpu?: number;

/**
* The hard limit (in MiB) of memory to present to the container.
*
* If your container attempts to exceed the allocated memory, the container
* is terminated.
*
* At least one of memoryLimitMiB and memoryReservationMiB is required for non-Fargate services.
*/
readonly memoryLimitMiB?: number;

/**
* The soft limit (in MiB) of memory to reserve for the container.
*
* When system memory is under contention, Docker attempts to keep the
* container memory within the limit. If the container requires more memory,
* it can consume up to the value specified by the Memory property or all of
* the available memory on the container instance—whichever comes first.
*
* At least one of memoryLimitMiB and memoryReservationMiB is required for non-Fargate services.
*/
readonly memoryReservationMiB?: number;
}
```

An example use case:
```ts
// Create the vpc and cluster used by the Queue Worker task
const vpc = new ec2.VpcNetwork(stack, 'Vpc', { maxAZs: 1 });
const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc });
cluster.addCapacity('DefaultAutoScalingGroup', {
instanceType: new ec2.InstanceType('t2.micro')
});

// Create the Queue Worker task
new Ec2QueueWorkerService(stack, 'EcsQueueWorkerService', {
cluster,
image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'),
desiredTaskCount: 2,
maxScalingCapacity: 5,
memoryReservationMiB: 512,
cpu: 256,
queueName: 'EcsWorkerQueue'
});
```

### Part 3: Create `FargateQueueWorkerServiceProps` interface and `FargateQueueWorkerService` construct

The `FargateQueueWorkerServiceProps` interface will contain properties to construct the FargateTaskDefinition, SQSQueue and FargateService:

```ts
/**
* Properties to define an Fargate service
*/
export interface FargateQueueWorkerServiceProps {
/**
* The number of cpu units used by the task.
* Valid values, which determines your range of valid values for the memory parameter:
* 256 (.25 vCPU) - Available memory values: 0.5GB, 1GB, 2GB
* 512 (.5 vCPU) - Available memory values: 1GB, 2GB, 3GB, 4GB
* 1024 (1 vCPU) - Available memory values: 2GB, 3GB, 4GB, 5GB, 6GB, 7GB, 8GB
* 2048 (2 vCPU) - Available memory values: Between 4GB and 16GB in 1GB increments
* 4096 (4 vCPU) - Available memory values: Between 8GB and 30GB in 1GB increments
*
* This default is set in the underlying FargateTaskDefinition construct.
*
* @default 256
*/
readonly cpu?: string;

/**
* The amount (in MiB) of memory used by the task.
*
* This field is required and you must use one of the following values, which determines your range of valid values
* for the cpu parameter:
*
* 0.5GB, 1GB, 2GB - Available cpu values: 256 (.25 vCPU)
*
* 1GB, 2GB, 3GB, 4GB - Available cpu values: 512 (.5 vCPU)
*
* 2GB, 3GB, 4GB, 5GB, 6GB, 7GB, 8GB - Available cpu values: 1024 (1 vCPU)
*
* Between 4GB and 16GB in 1GB increments - Available cpu values: 2048 (2 vCPU)
*
* Between 8GB and 30GB in 1GB increments - Available cpu values: 4096 (4 vCPU)
*
* This default is set in the underlying FargateTaskDefinition construct.
*
* @default 512
*/
readonly memoryMiB?: string;
}
```

An example use case:
```ts
// Create the vpc and cluster used by the Queue Worker task
const vpc = new ec2.VpcNetwork(stack, 'Vpc', { maxAZs: 2 });
const cluster = new ecs.Cluster(stack, 'FargateCluster', { vpc });

// Create the Queue Worker task
new FargateQueueWorkerService(stack, 'FargateQueueWorkerService', {
cluster,
image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'),
desiredTaskCount: 2,
maxScalingCapacity: 5,
queueName: 'FargateWorkerQueue'
});
```

0 comments on commit 3654a48

Please sign in to comment.