Files
nexus/sreweekly/articles/8/04-interview-building-the-latest-campaign-for-david-guetta-serverless-cod.html
2026-09-12 17:23:01 +08:00

312 lines
17 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="Ryan S. Brown">
<title>Interview: Building the Latest Campaign for David Guetta -- Serverless Code</title>
<link rel="stylesheet" href="/css/bootstrap-3.3.6.min.css">
<link href="/css/all.min.css?h=c3840cffae" rel="stylesheet">
<link href='https://fonts.googleapis.com/css?family=Merriweather:400,400italic,700|Open+Sans:300italic,400italic,600italic,700italic,400,300,600,700,800' rel='stylesheet' type='text/css'>
<script data-strip>
var __aerobatic__ = {staticAssetPath: ''};
</script>
</head>
<body>
<nav class="navbar navbar-default navbar-custom navbar-fixed-top">
<div class="container-fluid">
<div class="navbar-header page-scroll">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="https://serverlesscode.com/">Serverless Code</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">
<li>
<a href="/">Home</a>
</li>
<li>
<a href="/post/">Archives</a>
</li>
</ul>
</div>
</div>
</nav>
<header class="intro-header" style="background-image: url('/img/post-bg.jpg')">
<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
<div class="post-heading">
<h1>Interview: Building the Latest Campaign for David Guetta</h1>
<h2 class="subheading">Building an Infinitely Scaleable Online Recording Campaign for David Guetta</h2>
<span class="meta">Posted by
<a href="https://twitter.com/ryan_sb">Ryan S. Brown</a>
on Wed, Jan 13, 2016
<br />
In <a href="/categories/interview" >Interview</a>
<br />
Tags: <a href="/tags/lambda" >lambda</a>, <a href="/tags/api-gateway" >api gateway</a>, <a href="/tags/serverless-framework" >serverless framework</a>
</span>
</div>
</div>
</div>
</div>
</header>
<article>
<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
<p>Paging David Guetta fans: this week we have an interview with the team that
built the site behind his latest ad campaign. On the site, fans can record
themselves singing along to his single, &ldquo;This One&rsquo;s For You&rdquo; and build an album
cover to go with it.</p>
<p>Under the hood, the site is built on Lambda, API Gateway, and CloudFront.
Social campaigns tend to be pretty spiky &ndash; when there&rsquo;s a lot of press a
stampede of users can bring infrastructure to a crawl if you&rsquo;re not ready for
it. The team at <a href="https://parall.ax/">parall.ax</a> chose Lambda because there are no
long-lived servers, and they could offload all the work of scaling their app up
and down with demand to Amazon.</p>
<p>James Hall from <a href="https://parall.ax/">parall.ax</a> is going to tell us how they built an
internationalized app that can handle any level of demand from nothing in just
six weeks.</p>
<h2 id="the-interview">The Interview</h2>
<!-- raw HTML omitted -->
<p>Parallax is a digital agency; we provide a range of services including
application development, security and design services. We have 25 full-time
employees as well as some external contractors. We specialise in providing
massively scaleable solutions, with a particular focus on sports, advertising,
and FMCG (Fast Moving Consumer Goods).</p>
<!-- raw HTML omitted -->
<p>The app is part of a huge marketing campaign for David Guetta&rsquo;s new release
&ldquo;This One&rsquo;s For You&rdquo; &ndash; the official anthem of the UEFA EURO 2016 finals. We&rsquo;re
inviting fans &ndash; hopefully a million by March &ndash; into a virtual recording studio
and giving them the chance to sing along with Guetta. Not only will some of
their voices be included on the final song, we also create personalised album
artwork with their name and favourite team. This can be shared among friends,
increasing engagement and allowing more fans to become a part of the campaign.
The whole site has been built in twelve languages, incorporating video content
of the DJ himself and a chance to win a trip to Paris. You can check it out
over at <a href="https://thisonesforyou.com/">thisonesforyou.com</a>.</p>
<!-- raw HTML omitted -->
<p><img src="/images/guetta_article/image04.png" alt="AWS service architecture diagram" class="img-responsive">
<em>Image credit: Parallax Agency Ltd.</em></p>
<p>On the backend we use a variety of technologies to deliver a completely
scaleable architecture. We use <a href="http://serverless.com">Serverless</a> (formerly JAWS) and CloudFormation to
orchestrate the entire platform in code.</p>
<p>Requests are routed via CloudFront, with static assets cached at Edge locations
nearest to the user requesting them. When the page first loads, everything is
entirely static. A UUID is generated in the client browser - this is used for
all future API request and allows us to associate different actions in the page
together without having to serve cookies. The randomness of this value is
important, so the library uses timing and crypto functions (where available) to
derive random seed data.</p>
<p><img src="/images/guetta_article/image02.png" alt="CloudFormation and S3 integration diagram" class="img-responsive">
<em>Image credit: Amazon Web Services</em></p>
<p>The origin of the static assets is a simple S3 bucket. These are uploaded via a
script on deployment.</p>
<p>A language detection endpoint then sends back the Accept-Language header and
also country code that the request was received from. This is using a basic
Lambda function. Another endpoint adds subscriber data to DynamoDB, as well as
sending them a welcome email via Amazon SES. To make the recording work, we
have an endpoint which issues S3 tokens for a path named after the UUID
provided. Uploads are then directly posted to S3 from the browser.</p>
<p>The most useful application of Lambda was the image generation endpoint. We
take an image of the user&rsquo;s favourite team flag, overlay a picture of Guetta,
then add their name. This is then uploaded to S3, along with a Facebook and
Twitter sized graphic. We also upload a static HTML file, which points to this
unique graphic. This ensures when people share the URL it will display their
custom artwork. We use Open Graph image tags in the page for this.</p>
<p>On the frontend, we used Brunch to compile the handlebars templates, compile
SASS, prefix the CSS and any other build tasks.</p>
<p>The recording interface itself has three implementations. The &ldquo;A-grade&rdquo;
experience is the WebRTC recorder, which uses the new HTML5 functionality to
record directly from your microphone. We then have a Flash fallback for the
same experience, this is for desktop browsers without WebRTC support. Then
finally we have a file input that prompts users to record on mobile.</p>
<!-- raw HTML omitted -->
<p>Yes, absolutely. Our regular stack is LAMP, built on top of CloudFront, Elastic
Load Balancers and EC2 nodes. This would have scaled, but it would have been
much more difficult to scale as quickly and as simply as it is using a
Lambda-based architecture. We&rsquo;d have had to build a queueing system for the
image generation, then spin up EC2 nodes dedicated to making those images based
on the throughput.</p>
<p>Writing a simple Lambda function and letting Amazon do all the hard work seemed
like the obvious choice.</p>
<!-- raw HTML omitted -->
<p>The team at Parallax consisted of five people. Tom Faller was the Account
Manager, responsible for the day-to-day running of the project. I was the
backend developer creating the Lambda functions and designing the cloud
architecture. Amit Singh was primarily frontend, but worked on many of the glue
parts between the interface and the backend JS. Chris Mills was QA and Systems,
and linked to the Serverless (formerly JAWS) project in the first place. Jamie
Sefton was another JS developer and worked on integrating compatibility
fallbacks into the codebase, including a Flash-based and input-based recording
experience as a fallback for devices that don&rsquo;t support WebRTC. I&rsquo;ve had
experience with Lambda before, but it was new for the other team members.</p>
<!-- raw HTML omitted -->
<p>I&rsquo;d say around six or seven weeks in total, though there was plenty of research
and prototyping done beforehand to arrive at the correct architecture design.
For the amount of scalability required, it would have taken much longer to
ensure it was just as robust using our &ldquo;home turf&rdquo;.</p>
<!-- raw HTML omitted -->
<p>The application is deployed from Atlassian Bamboo. The codebase lives in Stash.
Each and every branch gets its own deployment URL which is posted into our
company chat once built. This lets us quickly test and decide if changes are
mergeable.</p>
<p><img src="/images/guetta_article/image05.png" alt="Lambda deployment bot in action" class="img-responsive">
<em>Image credit: Parallax Agency Ltd.</em></p>
<!-- raw HTML omitted -->
<p>For frontend JS errors we use Bugsnag; for this type of application this is the
easiest way to see if there&rsquo;s a problem anywhere in your stack. If error spikes
are bigger than traffic spikes you know something has gone wonky. We usually
use NewRelic for the backend, but as all the backend code lives in Lambda
functions we&rsquo;ve opted to use CloudWatch.</p>
<!-- raw HTML omitted -->
<p>Yeah absolutely. Every commit and branch pushed to Stash is deployed to a
testing environment. For the static assets and frontend JavaScript, this uses
bamboo, and creates a new folder for every branch and build number. For the
lambda functions, those were updated to each environment using <code>serverless dash</code>.</p>
<!-- raw HTML omitted -->
<p>The server Lambda runs on lacks any fonts with Japanese and Chinese characters,
which is to be expected, but wasn&rsquo;t something we&rsquo;d planned for in the
development. When an operating system renders a particular font and it doesn&rsquo;t
contain a particular glyph, it will fallback to the system installed
multilingual Unicode font. This happens on the web automatically, but inside
ImageMagick on a bare server this won&rsquo;t happen. This means we had to ship a
large Unicode font in our endpoint. We reduced the performance impact of this
by only routing non-Latin names to the Unicode endpoint.</p>
<p><img src="/images/guetta_article/image00.png" alt="Helvetica without unicode" class="img-responsive">
Helvetica, for example, doesn&rsquo;t include any Asian Glyphs
<img src="/images/guetta_article/image01.png" alt="Arial with unicode" class="img-responsive">
But Arial does</p>
<!-- raw HTML omitted -->
<p>There&rsquo;s some issues with multiple branches and the early Serverless (formerly
JAWS) framework. Say if we&rsquo;re adding an endpoint in one branch, and another in
another branch, they can&rsquo;t both be deployed to the same environment stage. This
is something we worked around, and we&rsquo;ll be looking to contribute some helpful
tools back to Serverless to deal with this.</p>
<!-- raw HTML omitted -->
<p>There are a couple of testing tools I’d highly recommend. Cameras and
microphones behave very differently in emulators - sometimes they’re not even
simulated at all! This means we had to use real devices for our testing. We
used a <a href="https://www.vanamco.com/devicelab/">Vanamco Device Lab</a> along with five devices that we consider to
be a good spread. We use this alongside Ghostlab which allows us to have the
same page open on all devices and keep them in sync. It includes a web
inspector to tweak CSS and run debugging JS. Then to increase Android coverage
we used <a href="http://testdroid.com/">testdroid</a>. This is a brilliant service that allows you to
use real devices remotely. Open the camera app and you can see inside a data
centre. I’ve been eagerly awaiting a testdroid engineer to poke his head into a
rack, but have so far been disappointed!</p>
<p><img src="/images/guetta_article/image03.png" alt="AWS service architecture diagram" class="img-responsive">
<em>Testdroid using a Google Nexus 10</em></p>
<h2 id="wrapping-up">Wrapping Up</h2>
<p>Thanks again to James Hall for the inside view on CI, mobile testing, and
Unicode workarounds for all-Lambda backends. To learn more about the
Serverless Application Framework, check out their <a href="http://serverless.com">site</a> or their
<a href="https://gitter.im/serverless/serverless">gitter.im chatroom</a>.</p>
<p><strong>Disclosure:</strong> I have no relationship to Parallax Agency Ltd., but they build
cool projects and this interview covers just one of them.</p>
<p>Keep up with future posts via <a href="https://serverlesscode.com/index.xml">RSS</a>. If you have suggestions, questions, or
comments feel free to email me
<!-- raw HTML omitted --><a href="mailto:ryan@serverlesscode.com">ryan@serverlesscode.com</a><!-- raw HTML omitted -->.</p>
<hr />
<p>
<a href="https://twitter.com/share?url=https%3a%2f%2fserverlesscode.com%2fpost%2fdavid-guetta-online-recording-with-lambda%2f&text=New%20ServerlessCode%20article%2c%20%22Interview%3a%20Building%20the%20Latest%20Campaign%20for%20David%20Guetta%22%20via%20%40ryan_sb">Tweet this</a>,
<a href="https://news.ycombinator.com/submitlink?u=https%3a%2f%2fserverlesscode.com%2fpost%2fdavid-guetta-online-recording-with-lambda%2f&t=Interview%3a%20Building%20the%20Latest%20Campaign%20for%20David%20Guetta">send to Hackernews</a>, or
<a href="http://www.reddit.com/submit?url=https%3a%2f%2fserverlesscode.com%2fpost%2fdavid-guetta-online-recording-with-lambda%2f&title=Interview%3a%20Building%20the%20Latest%20Campaign%20for%20David%20Guetta%20on%20serverlesscode.com">post on Reddit</a>
</p>
</div>
</div>
</div>
</article>
<hr>
<footer>
<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
<ul class="list-inline text-center">
<li>
<a href="/index.xml">
<span class="fa-stack fa-lg">
<i class="fa fa-circle fa-stack-2x"></i>
<i class="fa fa-rss fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
<li>
<a href="https://twitter.com/ryan_sb">
<span class="fa-stack fa-lg">
<i class="fa fa-circle fa-stack-2x"></i>
<i class="fa fa-twitter fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
<li>
<a href="https://github.com/ryansb">
<span class="fa-stack fa-lg">
<i class="fa fa-circle fa-stack-2x"></i>
<i class="fa fa-github fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
</ul>
<p class="copyright text-muted">© 2016 Ryan Scott Brown. Code released under the Apache 2.0 license.</p>
</div>
</div>
</div>
</footer>
<script src="/js/jquery-2.1.1.min.js"></script>
<script src="/js/bootstrap-3.3.6.min.js"></script>
<script src="/js/all.min.js?h=664ecf0284"></script>
<link rel="stylesheet" href="/css/font-awesome-4.5.0.min.css">
<script>hljs.initHighlightingOnLoad();</script>
</body>
</html>