In most cases, when users start to access and use a new application or a new release, app performs pretty well. As the user base grows and usage increases, the app can outgrow its infrastructure. Users can start experiencing a dip in performance. Latency increases, bandwidth and memory get exhausted quickly, and some code architectures start to fail because they do not scale well with the increased amount of users. This is not an unexpected issue; infrastructure and application architecture are meant to scale with increased usage. The risk is not knowing ahead of time when the application will ‘break’ or when the infrastructure will go down because there is increased load on the server. This issue can lead to big losses especially in financial terms.

Load testing is one of the most important kinds of testing in the software application lifecycle. With load tests, you can subject your application to the type of pressures expected in production. That gives you the information to fine-tune infrastructure and architectures, making sure that your application does not dip below your performance thresholds.

In this tutorial, we will be load testing a simple Node.js API using Apache benchmark, a load testing and benchmarking tool for HTTP servers.

Prerequisites

To follow this tutorial, a few things are required:

  1. Basic knowledge of Javascript
  2. Node.js installed on your system (version >= 10.3)
  3. A Heroku account
  4. A CircleCI account
  5. A GitHub account

With all these installed and set up, we can begin the tutorial.

Setting up Heroku for hosting

The first step is to set up a Heroku application to host our API. Navigate to your Heroku apps dashboard. Click New, then Create new app. Using the name you prefer, create a new app.

New App - Heroku

Take note of the app name (node-loadtest here) you just entered. You will need this later on during the tutorial.

Next, locate your Heroku API Key in the Account Settings section of your dashboard.

Heroku token

You will also need this later in the tutorial.

Cloning the test project

For the next step, you will need to clone the API project. The API project is a simple Node.js API application with a root endpoint and another endpoint for fetching a collection of users. Clone the project by running this command:

git clone --single-branch --branch base-project https://github.com/coderonfleek/node-loadtest

Once the cloning process is complete, go into the root of the project and install the dependencies by running these commands:

cd node-loadtest
npm install

When the installation is complete, run the application with the command:

npm start

The application will start listening on a default port of 3000. Open up Postman and make a GET request to the http://localhost:3000/users/get endpoint. This should return an array of users.

Get Users - Postman

Result? The API seems to be working fine.

Connecting to CircleCI

To set up the API project on CircleCI, you first need to push the project to GitHub.

Next, go to the Projects page on the CircleCI dashboard (Select the appropriate GitHub account) to add the project.

Add Project - CircleCI

Click the Set Up Project button to begin. This will load the next screen.

Add Config - CircleCI

On the setup page, click Use Existing Config to instruct CircleCI that we are adding a configuration file manually and not using the sample displayed. Next, you will be prompted to either download a configuration file for the pipeline or to start building.

Build Prompt - CircleCI

Click Start Building. This build will fail because we have not set up our configuration file yet. We will complete this step later on.

The final thing we need to do on the CircleCI console is to set up environment variables for the project we just added. This will enable our project to have authenticated access to our Heroku application for deployments.

Go to your project’s settings by clicking the Project Settings button on the Pipelines page. Make sure your project is the currently selected project.

Project settings - CircleCI

On the Project Settings page, click Environment Variables (it is in the side menu).

On the Environment Variables page, click Add Environment Variable.

Add Environment variable - CircleCI

Add the following environment variables:

  • HEROKU_APP_NAME is the name of your Heroku application (in this case cci-node-loadtest)
  • HEROKU_API_KEY is your Heroku account API key (mentioned earlier).

Environment variable - CircleCI

You now have everything set up on your CircleCI console for deployment to Heroku.

Adding the load test in the pipeline configuration

It is now time to build the deployment pipeline that will load test the API’s /users/get endpoint each time a deployment is made. At the root of your project, create a folder named .circleci and a file named config.yml within it. Inside config.yml, enter this code:

jobs:
  build:
    executor: heroku/default
    steps:
      - checkout
      - heroku/install
      - heroku/deploy-via-git

  loadtestapi:
    docker:
      - image: circleci/node:10.16.3
    steps:
      - run:
          name: Run Load Test
          command: |
            sudo apt-get update
            sudo apt-get install apache2-utils
            ab -k -c 20 -n 250 https://$HEROKU_APP_NAME.herokuapp.com/users/get

orbs:
  heroku: circleci/heroku@0.0.10
version: 2.1
workflows:
  deploy:
    jobs:
      - build
      - loadtestapi:
          requires:
            - build

In the configuration you just created, there are two jobs:

  • The build job uses CircleCI’s Heroku orb to deploy the API project from the GitHub repository to the Heroku app created on the hosting platform

  • Once the API is deployed, the loadtestapi installs the Apache benchmark tool then uses the tool to send 250 requests to the /users/get endpoint using a concurrency of 20 and a Keep-Alive connection type for a persistent connection with the -k flag

Using workflows, the loadtestapi job will not run until the build job is complete, ensuring that we do not run the load test until the API is successfully deployed.

Time to run the load test pipeline. Commit all changes to the project and push to your remote Github repository. This will automatically trigger the pipeline and you should have a successful build.

Build Successful - CircleCI

Click the loadtestapi job in the workflow to review the results of the load test.

Build Details - CircleCI

The results show that all 250 requests were served within 0.44 seconds. Whether this is a good result or not depends on the performance metrics set for your application by you or by your organization. Other details are shown that detail how the tests ran. These details can be useful in tuning your application architecture to better scale for thousands to millions of users using the application.

Conclusion

Any enterprise or startup organization serving software to users should take load tests seriously. Load testing enables you to avoid the consequences of downtime while users make use of the application. In this tutorial, we have been able to deploy an API and immediately run a load test to verify its capability to handle web traffic. There are many ways to extend these load tests using Apache benchmark. There are also specialized tools that can be plugged into the process or used as a replacement for Apache benchmark, like k6.

Happy coding!


Fikayo Adepoju is a Full-stack developer, technical writer, and tech content creator proficient in Web and Mobile technologies and DevOps with over 10 years experience developing scalable distributed applications. With over 40 articles written for CircleCI, Twilio, Auth0, and The New Stack blogs and also on his personal Medium page, he loves to share his knowledge to as many developers as would benefit from it. You can also check out his video courses on Udemy.