This course is still being built. Content will change. Get updates on the mailing list.

Review 2

You'll learn
  • How we're using the database for shared state.
  • How we're using the queue for offloading work from the main request path.

It's time for another review of what we've built. Queue the elevator music, we're going up into the cloud! ๐Ÿ›—โ˜๏ธ

Elevator music button

Shared state in the database

We're now storing our newsletter subscribers in the database. What does that mean, and what implications does it have?

It means that our app containers do not store any state, for one. It doesn't matter if one of them goes down or that you suddenly want 100 containers running because of all the traffic you're getting. As long as the database (or database cluster) is the right size to handle it, we can add as many app containers as we want and need.

It also means that in our setup, the database is a single point of failure. That means that if the database is down, our app is down. Remember how we're pinging the database in the health endpoint? So if we can't ping it from an app container, the load balancer doesn't route traffic to that container. So if the database is down, all app containers are also effectively down.

If this is unacceptable for your app, you can create a high-availability database instead in Lightsail. This means that instead of a single database instance, you get a cluster of database instances that replicate from one another. (The exact replication mechanism doesn't matter right now.) The instances are spread across availability zones, so they are as isolated as possible, to ensure that if one fails for some reason, the other doesn't. Failover from one database instance to the other is automatic, and usually takes a few milliseconds. Much better than being down for minutes or hours. ๐Ÿ˜Ž

Using the job queue

As I already mentioned shortly when setting up the queue, offloading work away from the request path has some really useful properties.

First, the request and response is much faster. Sending a message to the job queue is really fast, mostly even faster than writing to the database. Fast web apps are nice! Don't leave your visitors waiting more than they have to.

This also frees up resources on the app containers faster, so a single app container can handle more concurrent requests than otherwise possible.

If your app suddenly has a storm of visitors that sign up for the newsletter, maybe the email sending service wouldn't be able to keep up with your demand, or you could be rate-limited. When using the job queue, messages can just keep coming in, and the job runner will process them one at a time. Again, your visitors don't have to wait for it, or worse: see errors when trying to sign up.

Instead of sending out emails, consider a job that does some heavy computation. Maybe each job takes seconds or minutes or even longer. With the job queue, you could scale the number of app containers that process jobs independently from app containers that take requests, or run those app instances on different, more powerful machines. All because you've decoupled the request/response cycle from the jobs.

So are there any downsides to using a queue? Of course. Everything is a trade-off in distributed systems, and the answer to "Is it a good idea?" is almost always "It depends". Consider this:

  • A queue introduces another external resource to your app that could go down. If SQS is down, no signup requests can go through in your app. It's arguably not as bad as your database being down though.
  • There's a non-zero chance that a message will be delivered more than once. This is because guaranteeing exactly-once delivery is not possible in distributed systems, so your jobs have to take this into account. When sending emails, there's really nothing you can do about it: either the email gets sent or it doesn't. So we'll have to live with the fact that some emails can go out twice in failure cases. That's probably okay.
Bonus: Exactly-once delivery

A note about CDNs

Did you think about that we now have an app that serves a marketing site? If not, no worries. But let me explain: It's traditional to divide your website into the marketing part and the actual web app part. Often, different systems serve each of these, for example having Wordpress for the marketing site and our app for, well, the app part.

In our case, the app serves both the marketing site and the web app. (So does the course site you're reading this on.) What if you have many more visitors to your marketing site than to your app? Isn't it nice to be able to scale those independently?

If that is a concern to you, you can always reach for another basic building block in cloud computing: the . By letting a CDN act as a cache to serve most of your (static) marketing website traffic, most requests will never reach your app containers.

What's next?

Now that we've had a deeper look at what it means to have a database and a queue for our newsletter feature, it's time to make sure that we have insight into our running app. We'll be looking at observability and alerting, so that we can see how our app behaves in the cloud, and get notified if something goes wrong.

The music is licensed from Kevin MacLeod, the elevator sound is licensed from Trautwein, both under a Creative Commons By 3.0 license.

Review questions

Sign up or log in to get review questions by email! ๐Ÿ“ง

Questions?

Get help on Twitter or by email.