As the cold months roll in, it’s time to make sure your WebSockets are snug and hole-free, just like your favorite pair of winter socks. In this post, I’ll show you how to load-test your socket connections. Nobody wants holes in their SOCKet—keeping things warm, cozy, and performing smoothly, no matter the load!

Table of Contents

Introduction

Bringing real-time behavior to your solution is not just for the big players anymore—it’s easy to integrate! For this project, the goal was to add real-time updates (both attended and unattended) to a news feed that displays SharePoint Online news.

You can find the complete code for the PuntoBello Realtime News here , and see how to load-test your Azure web app here .

%%{init: {'theme': 'base', 'themeVariables': { 'background': '#CFA63D', 'primaryColor': '#CFA63D', 'primaryTextColor': '#0aa8a7', 'primaryBorderColor': '#c7a42b', 'secondaryColor': '#e6e6e6', 'secondaryTextColor': '#333333', 'secondaryBorderColor': '#999999', 'lineColor': '#e74c3c', 'fontFamily': 'ui-sans-serif,system-ui,-apple-system,BlinkMacSystemfont,sans-serif', 'fontSize': '14px', 'actorBorderColor': '#2980b9', 'actorBkgColor': '#ffcc00', 'actorTextColor': '#225f78', 'labelBoxBkgColor': '#ffffff', 'labelBoxBorderColor': '#cccccc', 'labelTextColor': '#000000', 'noteBkgColor': '#E5E4E2', 'noteTextColor': '#225f78', 'noteBorderColor': '#bbbab8', 'sequenceNumberColor': '#e67e22', 'taskBkgColor': '#3498db', 'taskBorderColor': '#2980b9', 'taskTextColor': '#ffffff' }}}%% sequenceDiagram participant U as Users participant P as Publisher participant L as Logic App participant SB as Service Bus Queue participant WA as Web App (Node.js) participant SPFx as SPFx WebPart P->>L: Publishes a news item L->>SB: Item created, Logic App triggers and sends payload SB->>WA: Service Bus Queue delivers payload to Web App WA->>SPFx: Web App sends payload to SPFx WebPart via socket.io SPFx->>U: SPFx WebPart renders update on News Feed

The flow is pretty straightforward. Here’s what we have:

  • An SPFx web part
  • An Azure web app running a Node.js server

The SPFx web part connects to the Azure web app using the Socket.IO library , an open-source real-time framework for Node.js.

This post focuses on how to set up and load-test your Azure web app so that you can:

  • Fine-tune and validate your client- and server-side setup
  • Determine the appropriate Azure Service Plans for your workload or organization

Development Setup

Before deploying your web app to Azure, it’s good practice to test locally. Since our web app is essentially a Node.js server and the client code is JavaScript, it’s easy to implement and test locally.

You can find detailed instructions on setting up your environment locally here .

Load Testing

Load testing helps fine-tune our setup and validate parameters such as:

  • Client and server configurations (e.g., timeouts)
  • The appropriate App Service Plan for simulating production load

Artillery

Artillery is a powerful load-testing framework for any web stack, including Socket.IO. You can define your load test in a YAML file and easily simulate large numbers of clients.

Here’s an example configuration:

config:
  target: "{{ $processEnvironment.PUNTOBELLO_TARGET_URL }}"   # the URL of your socket.io server in the format wss://your-url.com
  phases:
    - duration: 1200
      arrivalRate: 10
      rampTo: 20
      name: "Increasing load"
  engines:
    socketio-v3:
      pingInterval: 40000
      pingTimeout: 30000
      transports: ["websocket"]
scenarios:
  - name: Load test PuntoBello PubSub
    engine: "socketio-v3"
    flow:
      - connect:
          url: "{{ $processEnvironment.PUNTOBELLO_TARGET_URL }}" # the URL of your socket.io server in the format wss://your-url.com
      - think: 600  # Wait for 10 minutes before disconnecting
      - disconnect

In this configuration:

  • The target and connect URL are set using the environment variable PUNTOBELLO_TARGET_URL.
  • The test runs for 1200 seconds (20 minutes) with an initial arrival rate of 10 clients per second, ramping up to 20 clients per second by the end of the phase.
  • Socket.IO parameters like pingInterval and pingTimeout are set.
  • Each client stays connected for 600 seconds (10 minutes).

The total number of clients during the ramp phase can be calculated as:

Total clients during ramp = (10 + 20) / 2 × 1200 = 15 × 1200 = 18,000 clients

For this load test, you’ll likely need to run a Premium App Service Plan on Azure.

Note: Artillery is a highly flexible framework that allows you to simulate various scenarios and add phases as needed.

Running the Load Test

Assuming the configuration is saved in a file called loadtest.yml, you can start your test with the following command:

npx artillery run loadtest.yml

Note: You will need to install all dependencies using npm install and ensure that npx is available.

When everything runs smoothly, the output in your terminal will look something like this:

Phase started: Increasing load (index: 0, duration: 1200s) 20:39:06(+0200)

--------------------------------------
Metrics for period to: 20:39:10(+0200) (width: 3.443s)
--------------------------------------

vusers.created: ................................................................ 39
vusers.created_by_name.Load test PuntoBello PubSub: ............................ 39

If your server becomes unreachable or overloaded, you’ll see errors like this:

Phase started: Increasing load (index: 0, duration: 1200s) 20:39:06(+0200)

--------------------------------------
Metrics for period to: 20:39:10(+0200) (width: 3.443s)
--------------------------------------

errors.websocket error: ........................................................ 37
vusers.created: ................................................................ 39
vusers.created_by_name.Load test PuntoBello PubSub: ............................ 39
vusers.failed: ................................................................. 37

Debugging Artillery

If things don’t work as expected, you can enable more detailed logs. Artillery supports Node.js-style debugging by prefixing your command with DEBUG.

To debug Socket.IO:

DEBUG=socketio npx artillery run loadtest.yml

To debug everything:

DEBUG=* npx artillery run loadtest.yml

Key Points

Never Load-Test Against Production

This might seem obvious, but always avoid load-testing your production environment. Load testing can create significant traffic, which might disrupt your normal users.

Every Server Has Its Limit

That’s why we load test—to identify optimal configurations. It’s important to set reasonable load-testing parameters. For example, simulating 100 clients per second equates to 6,000 clients per minute, which is rare in most corporate environments.

Conclusion

Socket.IO makes it easy to integrate real-time functionality into Microsoft 365 solutions. Load-testing your components with Artillery ensures they’re production-ready and able to handle the expected load.