Scaling for success: load testing your app for Black Friday – part 2

Scaling for success on Black Friday isn’t just about adding more servers—it’s about understanding your application’s limits and optimizing performance under extreme conditions. Load testing provides the insights needed to fine-tune your infrastructure and code, guaranteeing a smooth user experience when it matters most.

By Thomas di Luccio, on Aug 14, 2024

In the first installment of this series, we explored the reasons for load testing, which can help you better control your application’s breaking points and ensure it can successfully handle the heavy traffic you intend to drive on it during Black Friday and other special events.

Today, we are putting our hopes into action and will code a load-testing tool to complement our performance and observability apparatus. Let’s grab your favorite surfboard and ride the intense traffic wave like a pro!

Choose your weapon, and fire up requests!

Now that we have an environment we can work on, we need a tool to perform load testing. Gatling and Locust are two great solutions for that. Gatling has the advantage of proposing a SaaS version of the tool. You could also install an open-source version of the tool for Java, Kotlin, Scala, JavaScript, or TypeScript environments.Locust is a fully open-source Python application. At Blackfire, we love Python as much as we love OSS. Let’s go with Locust! The installation procedure couldn’t be more straightforward:

pip3 install locust

Yes! That’s it. One line is enough to have a load-testing tool installed. You can then create your first test. For that, create a locustfile.py file containing this example:

from locust import HttpUser, task

class HelloWorldUser(HttpUser):
    @task
    def hello_world(self):
        self.client.get("/hello")
        self.client.get("/world")

Locust comes with a convenient UI that can be launched with another straightforward command:

$ locust

Starting web interface at http://0.0.0.0:8089
Starting Locust 2.29.1

All you have to do is set your level of expectation in terms of peak concurrency and point to the custom environment you created for the occasion. However, our configuration file might be too minimalistic for the test to be interesting at this point. Let’s enrich it.

Monkey test the critical user journeys

The logic of a locustfile is to describe specific scenarios within functions using the @task decorator. Those functions will then be randomly called during the actual load test. This approach is called monkey testing.

Monkey testing is a technique in which the application is tested by providing random inputs and actions to check for unexpected crashes, behaviors, or errors. It’s often performed in a way that simulates unpredictable user behavior and identifies potential vulnerabilities. The @task decorator accepts an optional weight argument that can be used to specify the task’s execution ratio. The higher the value, the more likely this individual task will be selected.

import time
from locust import HttpUser, task

class HelloWorldUser(HttpUser):

@task(5)
def homepage(self):
    self.client.get("/")

@task
def miscellaneous(self):
    self.client.get("/about")
    self.client.get("/login")

@task(5)
def view_sightings(self):
    for item_id in range(50):
        self.client.get(f"/sighting/{item_id}", name="/sighting")
        time.sleep(1)

@task(10)
def view_sighting_135(self):
    # that critital and resource-intensive page
    self.client.get("/sighting/135")

Locust’s documentation provides in-depth information on writing advanced locustfiles. You will have no difficulty finding your way and building the custom test file you need in no time.

At this point in your journey toward handling heavy traffic, you can work on a carbon copy of your application and the foundation of load testing and traffic generation using Locust.

In the third and last installment of this series, we will go even further, enrich our locustfiles, and prepare the automation of those tests to lower the cost and complexity of running them as frequently as necessary so you can achieve your objectives.

To better observability and beyond


The “Scaling for success: load testing your app for Black Friday” series:

Thomas di Luccio

Thomas is a Developer Relations Engineer at Platform.sh for Blackfire.io. He likes nothing more than understanding the users' needs and helping them find practical and empowering solutions. He’ll support you as a day-to-day user.