Skip to content
Open
24 changes: 15 additions & 9 deletions script/prerender/cfn.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ Parameters:
AllowedPattern: ^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\dZ$
ConstraintDescription: Must be a timestamp in the YYYY-MM-DDTHH:MM:SSZ format

TotalMemoryMiB:
Description: Total fleet memory capacity in MiB (must equal desired task count * 4096)
TotalVCpuCount:
Description: Total fleet vCPU capacity (must equal desired task count * 2)
Type: Number
MinValue: 4096
ConstraintDescription: Must equal desired task count * 4096
MinValue: 2
ConstraintDescription: Must equal desired task count * 2
Comment thread
Dantemss marked this conversation as resolved.

Resources:

Expand Down Expand Up @@ -81,6 +81,7 @@ Resources:
ContainerDefinitions:
- Command:
- prerender:work
Cpu: 2048
EntryPoint:
- yarn
Environment:
Expand Down Expand Up @@ -109,7 +110,7 @@ Resources:
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: workers
mode: non-blocking
MemoryReservation: 4096
MemoryReservation: 3686

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apparently there's some memory overhead on every instance so this has to be slightly lower than the value we aim for (4GB).

Name: !Sub ${AWS::StackName}-task-definition
Family: Prerendering
NetworkMode: host
Expand All @@ -123,6 +124,13 @@ Resources:
EnableECSManagedTags: true
EnableExecuteCommand: true
LaunchType: EC2
PlacementStrategies:
- Field: attribute:ecs.availability-zone
Type: spread
- Field: cpu
Type: binpack
- Field: memory
Type: binpack

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In theory this is supposed to try to fill the existing instances as much as possible

PropagateTags: SERVICE
ServiceName: Prerendering
TaskDefinition: !Ref TaskDefinition
Expand Down Expand Up @@ -198,9 +206,7 @@ Resources:
MaxSpotPriceAsPercentageOfOptimalOnDemandPrice: 101
MemoryGiBPerVCpu:
Min: 2
Max: 8
MemoryMiB:
Max: !Ref TotalMemoryMiB
Min: 4096
VCpuCount:
Min: 2
Expand All @@ -223,8 +229,8 @@ Resources:
Value: !Sub ${AWS::StackName}-fleet
TargetCapacitySpecification:
DefaultTargetCapacityType: spot
TargetCapacityUnitType: memory-mib
TotalTargetCapacity: !Ref TotalMemoryMiB
TargetCapacityUnitType: vcpu
TotalTargetCapacity: !Ref TotalVCpuCount
TerminateInstancesWithExpiration: true
ValidUntil: !Ref ValidUntil

Expand Down
10 changes: 5 additions & 5 deletions script/prerender/fleet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ import { RELEASE_ID, WORK_REGION, BUCKET_NAME, BUCKET_REGION, PUBLIC_URL } from
const MAX_CONCURRENT_BOOKS = 5;

// Number of concurrent prerender tasks to run
const DESIRED_TASK_COUNT = 32;
const DESIRED_TASK_COUNT = 16;

// Total fleet memory capacity in MiB (must equal DESIRED_TASK_COUNT * 4096)
const TOTAL_MEMORY_MIB = DESIRED_TASK_COUNT * 4096;
// Total fleet vCPU capacity (must equal DESIRED_TASK_COUNT * 2)
const TOTAL_VCPU_COUNT = DESIRED_TASK_COUNT * 2;
Comment thread
Dantemss marked this conversation as resolved.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

32 vCPU seems to make the prerendering finish in a timely manner, about 25 minutes when everything goes well.

I decided I wanted 16 tasks (containers) with 2 vCPU each, and each task spawns 2 threads so they can use both vCPU. This is mostly based on wanting things to run on at least 1 full Intel core. Maybe 3 or 4 threads could work better, but determining that would require some actual benchmarking.


// Retry EPROTO errors in requests this many times
const MAX_ATTEMPTS = 5;
Expand Down Expand Up @@ -200,8 +200,8 @@ async function createWorkersStack() {
ParameterValue: RELEASE_ID,
},
{
ParameterKey: 'TotalMemoryMiB',
ParameterValue: TOTAL_MEMORY_MIB.toString(),
ParameterKey: 'TotalVCpuCount',
ParameterValue: TOTAL_VCPU_COUNT.toString(),
},
{
ParameterKey: 'ValidUntil',
Expand Down
3 changes: 1 addition & 2 deletions script/prerender/work.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ import './logUnhandledRejectionsAndExit';
// The timeout must be long enough to render the slowest page, otherwise builds will never finish
const MAX_HEARTBEATS = 20;

// Since SchedulingStrategy switched from DAEMON to REPLICA, MemoryReservation controls how many
// tasks each instance gets; at a 2 GiB/vCPU floor, a 4096 MiB task can get up to 2 vCPUs
// Each task reserves 2 vCPUs, one per thread
const WORKER_THREAD_COUNT = 2;

console.log(`Bucket: ${process.env.BUCKET_NAME} (${process.env.BUCKET_REGION})`);
Expand Down
Loading