Skip to content

Commit

Permalink
feat(deadline): add ability to horizontally scale the RenderQueue (#301)
Browse files Browse the repository at this point in the history
  • Loading branch information
kozlove-aws authored Jun 3, 2021
1 parent b800b6f commit 8a55f32
Show file tree
Hide file tree
Showing 3 changed files with 203 additions and 59 deletions.
25 changes: 19 additions & 6 deletions packages/aws-rfdk/lib/deadline/lib/render-queue-ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ export interface RenderQueueSizeConstraints {
* If this is set to a number, every deployment will reset the number of RCS processes
* to this number. It is recommended to leave this value undefined.
*
* Currently, the Deadline RCS does not properly support being horizontally scaled behind a load-balancer. For this
* reason, the desired number of processes can only be set to 1 currently.
* Deadline versions earlier than 10.1.10 do not support being horizontally scaled behind a load-balancer.
* For these versions of Deadline, the desired number of processes can only be set to 1.
*
* @default The min size.
*/
Expand All @@ -87,14 +87,27 @@ export interface RenderQueueSizeConstraints {
/**
* Minimum number of Deadline RCS processes that will serve RenderQueue requests.
*
* Currently, the Deadline RCS does not properly support being horizontally scaled behind a load-balancer. For this
* reason, the minimum can be at most one, otherwise an error is thrown.
* Deadline versions earlier than 10.1.10 do not support being horizontally scaled behind a load-balancer.
* For these versions of Deadline, the minimum number of processes can only be set to 1, otherwise an error is thrown.
*
* The minimum that this can value be set to is 1.
* The minimum that this value can be set to is 1.
*
* @default 1
*/
readonly min?: number;

/**
* Maximum number of Deadline RCS processes that will serve RenderQueue requests.
*
* Deadline versions earlier than 10.1.10 do not support being horizontally scaled behind a load-balancer.
* For these versions of Deadline, the maximum number of processes can only be set to 1, otherwise an error is thrown.
*
* The minimum that this value can be set to is 1.
* This value cannot be less than `min` or `desired`.
*
* @default 1
*/
readonly max?: number;
}

/**
Expand Down Expand Up @@ -283,7 +296,7 @@ export interface RenderQueueProps {
* Constraints on the number of Deadline RCS processes that can be run as part of this
* RenderQueue.
*
* @default Allow no more and no less than one Deadline RCS to be running.
* @default Allow no less than one Deadline RCS to be running.
*/
readonly renderQueueSize?: RenderQueueSizeConstraints;

Expand Down
42 changes: 33 additions & 9 deletions packages/aws-rfdk/lib/deadline/lib/render-queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ import {
IRepository,
IVersion,
RenderQueueProps,
RenderQueueSizeConstraints,
VersionQuery,
} from '.';

Expand All @@ -82,6 +83,7 @@ import {
import {
RenderQueueConnection,
} from './rq-connection';
import { Version } from './version';
import {
WaitForStableService,
} from './wait-for-stable-service';
Expand Down Expand Up @@ -171,6 +173,11 @@ export class RenderQueue extends RenderQueueBase implements IGrantable {
[ApplicationProtocol.HTTPS]: 4433,
};

/**
* The minimum Deadline version required for the Remote Connection Server to support load-balancing
*/
private static readonly MINIMUM_LOAD_BALANCING_VERSION = new Version([10, 1, 10, 0]);

/**
* Regular expression that validates a hostname (portion in front of the subdomain).
*/
Expand Down Expand Up @@ -247,6 +254,12 @@ export class RenderQueue extends RenderQueueBase implements IGrantable {
*/
private readonly rqConnection: RenderQueueConnection;

/**
* Constraints on the number of Deadline RCS processes that can be run as part of this
* RenderQueue.
*/
private readonly renderQueueSize: RenderQueueSizeConstraints;

/**
* The listener on the ALB that is redirecting traffic to the RCS.
*/
Expand All @@ -265,12 +278,19 @@ export class RenderQueue extends RenderQueueBase implements IGrantable {
constructor(scope: Construct, id: string, props: RenderQueueProps) {
super(scope, id);

// The RCS does not currently support horizontal scaling behind a load-balancer, so we limit to at most one instance
if (props.renderQueueSize && props.renderQueueSize.min !== undefined && props.renderQueueSize.min > 1) {
throw new Error(`renderQueueSize.min cannot be greater than 1 - got ${props.renderQueueSize.min}`);
}
if (props.renderQueueSize && props.renderQueueSize.desired !== undefined && props.renderQueueSize.desired > 1) {
throw new Error(`renderQueueSize.desired cannot be greater than 1 - got ${props.renderQueueSize.desired}`);
this.renderQueueSize = props?.renderQueueSize ?? {min: 1, max: 1};

if (props.version.isLessThan(RenderQueue.MINIMUM_LOAD_BALANCING_VERSION)) {
// Deadline versions earlier than 10.1.10 do not support horizontal scaling behind a load-balancer, so we limit to at most one instance
if ((this.renderQueueSize.min ?? 0) > 1) {
throw new Error(`renderQueueSize.min for Deadline version less than ${RenderQueue.MINIMUM_LOAD_BALANCING_VERSION.toString()} cannot be greater than 1 - got ${this.renderQueueSize.min}`);
}
if ((this.renderQueueSize.desired ?? 0) > 1) {
throw new Error(`renderQueueSize.desired for Deadline version less than ${RenderQueue.MINIMUM_LOAD_BALANCING_VERSION.toString()} cannot be greater than 1 - got ${this.renderQueueSize.desired}`);
}
if ((this.renderQueueSize.max ?? 0) > 1) {
throw new Error(`renderQueueSize.max for Deadline version less than ${RenderQueue.MINIMUM_LOAD_BALANCING_VERSION.toString()} cannot be greater than 1 - got ${this.renderQueueSize.max}`);
}
}

this.version = props?.version;
Expand Down Expand Up @@ -315,12 +335,16 @@ export class RenderQueue extends RenderQueueBase implements IGrantable {
if (minCapacity < 1) {
throw new Error(`renderQueueSize.min capacity must be at least 1: got ${minCapacity}`);
}
const maxCapacity = this.renderQueueSize.max ?? this.renderQueueSize?.desired;
if (this.renderQueueSize?.desired && maxCapacity && this.renderQueueSize?.desired > maxCapacity) {
throw new Error(`renderQueueSize.desired capacity cannot be more than ${maxCapacity}: got ${this.renderQueueSize.desired}`);
}
this.asg = this.cluster.addCapacity('RCS Capacity', {
vpcSubnets: props.vpcSubnets ?? { subnetType: SubnetType.PRIVATE },
instanceType: props.instanceType ?? new InstanceType('c5.large'),
minCapacity,
desiredCapacity: props.renderQueueSize?.desired,
maxCapacity: 1,
desiredCapacity: this.renderQueueSize?.desired,
maxCapacity,
blockDevices: [{
deviceName: '/dev/xvda',
// See: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-ami-storage-config.html
Expand Down Expand Up @@ -386,7 +410,7 @@ export class RenderQueue extends RenderQueueBase implements IGrantable {
this.pattern = new ApplicationLoadBalancedEc2Service(this, 'AlbEc2ServicePattern', {
certificate: this.clientCert,
cluster: this.cluster,
desiredCount: props.renderQueueSize?.desired,
desiredCount: this.renderQueueSize?.desired,
domainZone: props.hostname?.zone,
domainName: loadBalancerFQDN,
listenerPort: externalPortNumber,
Expand Down
Loading

0 comments on commit 8a55f32

Please sign in to comment.