Technology

Serverless-side Rendering: How we ensured Kanye’s midas touch didn’t break the internet

This is the story of how two DevOps-curious developers solved a very modern problem in a less than conventional way. If you’ve never heard of serverless-side rendering before, you’re not alone. That’s because I made it up. With the help of my colleague Kalle, we found a new way to use the Serverless Framework to solve a new kind of problem.

First of all, if the word ‘Yeezy’ doesn’t mean anything to you, find your nearest teenager and ask them.

Got it? Great! The Kanye West-designed shoe, manufactured by our client adidas, is something of a cultural phenomenon. Not just in its design or marketing, but the way in which it is sold. As your generational consultant may have explained, new designs of Yeezys are sold in ‘drops’ – a sort of flash sale where forty thousand pairs can be sold in under two minutes, according to West himself.

You can already imagine the strain this would put on the adidas servers. However, there are additional complications: dozens of local markets and price points, constraints around SEO, etc. From a workflow point of view, we also had to maintain control of the project so we could roll out new features in time for the next drop.

So, let’s briefly go through what we were working with.

We inherited a marketing site that was essentially a jQuery “app”. The client-side rendering created issues with SEO, in that adidas wanted the metadata localized and the product information available without relying on client-side JavaScript. Given these constraints, we had two options:

  1. Render at build-time and deploy per market (since the content is unique for each market)
  2. Set up a server

The first is quite straightforward, but there’s a catch… Given that the product data changes frequently, and this needs to be kept up-to-date in Google search results, we’d need a continuous integration tool. adidas has one (great!), but it’s in a different team’s territory, so our team wouldn’t have control of the tools. On the other hand, setting up our own server would solve many of the issues, but also brings its own problems.

Finding a middle ground

Just like Goldilocks, we wanted to find something just right, a carefree non-server option that would let us render the metadata server-side before sending it to clients. Well, if you recall the title of this post, you won’t be surprised to hear that we found a solution!

AWS Lambda, a serverless computing platform, has two pitfalls:

  • Every call costs money
  • Cold starts – if the function hasn’t been called in a while, it will take more than a second to answer, which is an unacceptable experience for our Yeezy enthusiast.

Luckily for us, our client was using Akamai, so we had the luxury of being in their content delivery network. This vastly reduces the number of hits to AWS Lambda, keeping costs down. However, the cold start issue was a bit trickier. Since the cache needs to occasionally hit the origin, there will be a cold start from time to time – though preferably not when it’s trying to serve the end user. Akamai supports prefetching, so we configured it to proactively fetch the data for each market from the origin once per minute. This means that whenever an end user makes a request, they will be served up-to-date information, though it will result in some unnecessary hits to the origin. However, a quick calculation showed these costs to be negligible – a fraction of what one pair of Yeezys will set you back.

Eezy, right?

Despite the slightly unorthodox approach, we were able to solve the SEO problems without racking up a huge AWS bill or overloading adidas’s servers on drop day.

A JavaScript function deployed via AWS Lambda gathers the necessary product data and other metadata, and bakes it into the HTML that’s served (and easily read by Google). The React app is still rendered on the client-side, though there’s no reason why we couldn’t move more of the rendering to our Lambda setup in the future.

Handling our AWS “infrastructure” is a breeze with the Serverless Framework. Our configuration is around fifty lines of YAML (hey, we didn’t say it was perfect). We’ve been in production for almost one and half years now and our serverless-side rendering hasn’t caused any problems. Running the function locally with the serverless-offline plugin works nicely, too, so local development is no issue either.

This setup let us quickly switch focus to building features for the marketing site. I’m happy, Kalle is happy, the client is happy, and I’m sure those lucky enough to cop a pair of Yeezys are happy too.

Never miss a post