Skip to main content

Implementing Rollback in SSG with Cloudfront

Features

Since entire site is pre-rendered, difference in layout between mobile/desktop causes higher CLS.

Implementing Rollback in SSG with Cloudfront
Rollback using buildNumber
Part of Series: Statically Generated Sites
Table of Contents

The Problem

SSG Generates all the pages at build time, and hence with increasing pages, the build time increases. During an incident, re-generating the entire site after a fix will take time. Since the SSG has all the static content already, rollbacking to a previous build is often better while you resolve the incident.

Solution

Keep the previous builds

In your S3 bucket, while pushing the changes for a new build, instead of replacing the old files, we can just push into a new directory with buildNumber.

S3 Bucket Folder Structure
S3 Bucket
├── build_001
│ ├── index.html
│ ├── ...
├── build_002
│ ├── ...
├── build_003
│ ├── ...
└── build_004
├── ...

Configure a custom origin header in CF

Add a header in CDN’s origin configuration. This is always updated with the new release post syncing all the files to S3

To add buildVersion, navigate to the CF distribution and Select Origins -> Select Origin -> Edit -> Origin Custom Headers

Add Build Version

Make a given version live (forward / rollback)

version-deployment.sh
aws configure set aws_access_key_id "$AWS_ACCESS_KEY_ID"
aws configure set aws_secret_access_key "$AWS_SECRET_ACCESS_KEY"
aws configure set region "$AWS_DEFAULT_REGION"
aws cloudfront get-distribution --id $AWS_CF_DISTRIBUTION_ID > cf-config.json
Etag=$(cat cf-config.json | jq '.ETag' | tr -d \")
aws cloudfront get-distribution-config --id $AWS_CF_DISTRIBUTION_ID --query 'DistributionConfig' --output json > dist-config.json
cat dist-config.json | jq --arg newBuildVersion ${NEW_BUILD_NUMBER} '(.Origins.Items[].CustomHeaders.Items[] | select(.HeaderName == "buildVersion").HeaderValue) |= $newBuildVersion' > dist-config2.json
aws cloudfront update-distribution --id $AWS_CF_DISTRIBUTION_ID --distribution-config "file://dist-config2.json" --if-match "$Etag" > /dev/null
aws cloudfront wait distribution-deployed --id $AWS_CF_DISTRIBUTION_ID
aws cloudfront create-invalidation --distribution-id $AWS_CF_DISTRIBUTION_ID --paths "/*"
rm -f dist-config.json dist-config2.json cf-config.json

Use lambda@edge to add prefix in request URI

The lambda@edge will receive this buildNumber header, which it can use to prefix the request URI and hence serving the right file

Tags