No results for

Powered byAlgolia

WebSockets

suggest edits

Overview

WebSocket is a protocol that provides full-duplex communication channels over a single TCP connection. It is commonly used by single-page apps (SPAs), and to some extent mobile apps, to add server-push based functionality, which usually means a performance improvement over polling based solutions.

Load testing WebSockets with k6

Comparing HTTP based tests to WebSocket ones, there are some differences in the structure and inner workings. The primary difference is that instead of continuously looping the main function (export default function() { ... }) over an over, each VU is now setup to run an asynchronous event loop.

The basic structure of a WebSocket test looks like this:

Basic structure of WebSocket-based tests
1import ws from 'k6/ws';
2import { check } from 'k6';
3
4export default function () {
5 const url = 'ws://echo.websocket.org';
6 const params = { tags: { my_tag: 'hello' } };
7
8 const res = ws.connect(url, params, function (socket) {
9 socket.on('open', () => console.log('connected'));
10 socket.on('message', (data) => console.log('Message received: ', data));
11 socket.on('close', () => console.log('disconnected'));
12 });
13
14 check(res, { 'status is 101': (r) => r && r.status === 101 });
15}

As you can see above the connect() method takes a "run" function as its third parameter, and that function should accept a Socket object as its only parameter. The run function forms the basis of the asynchronous event loop.

It will be called immediately when the WebSocket connection is created, execute all code inside it (usually code to set up event handlers), and then block until the WebSocket connection is closed (by the remote host or by using socket.close()).

Error handling

To catch errors that can happen during the life of a WebSocket connection you attach a handler to the "error" event, as is illustrated below:

Error handling in WebSocket tests
1 import ws from "k6/ws";
2 import { check } from "k6";
3
4 export default function() {
5 const url = "ws://echo.websocket.org";
6 const params = { "tags": { "my_tag": "hello" } };
7
8 const res = ws.connect(url, params, function(socket) {
9 socket.on('open', function open() {
10 ...
11 });
12
13 socket.on('error', function(e) {
14 if (e.error() != "websocket: close sent") {
15 console.log('An unexpected error occured: ', e.error());
16 }
17 });
18 });
19
20 check(res, { "status is 101": (r) => r && r.status === 101 });
21 }

Timers

If you want to schedule a recurring action you can use the socket.setInterval function to specify a function that should be called with a particular interval.

Timers in WebSocket tests
1import ws from 'k6/ws';
2import { check } from 'k6';
3
4export default function () {
5 const url = 'ws://echo.websocket.org';
6 const params = { tags: { my_tag: 'hello' } };
7
8 const res = ws.connect(url, params, function (socket) {
9 socket.on('open', function open() {
10 console.log('connected');
11
12 socket.setInterval(function timeout() {
13 socket.ping();
14 console.log('Pinging every 1sec (setInterval test)');
15 }, 1000);
16 });
17
18 socket.on('ping', () => console.log('PING!'));
19 socket.on('pong', () => console.log('PONG!'));
20 socket.on('close', () => console.log('disconnected'));
21 });
22
23 check(res, { 'status is 101': (r) => r && r.status === 101 });
24}

Timeouts

You can add a timeout to the WebSocket connection by passing a handler function as well as the timeout value (in milliseconds) to the socket.setTimeout function.

Timeouts in WebSocket tests
1import ws from 'k6/ws';
2import { check } from 'k6';
3
4export default function () {
5 const url = 'ws://echo.websocket.org';
6 const params = { tags: { my_tag: 'hello' } };
7
8 const res = ws.connect(url, params, function (socket) {
9 socket.on('open', () => console.log('connected'));
10 socket.on('close', () => console.log('disconnected'));
11
12 socket.setTimeout(function () {
13 console.log('2 seconds passed, closing the socket');
14 socket.close();
15 }, 2000);
16 });
17
18 check(res, { 'status is 101': (r) => r && r.status === 101 });
19}

The timeout in the above code will close down the WebSocket connection after 2 seconds.

Multiple event handlers

You can attach multiple handler functions to an event as the code below illustrates.

Multiple event handlers in WebSocket tests
1import ws from 'k6/ws';
2import { check } from 'k6';
3
4export default function () {
5 const url = 'ws://echo.websocket.org';
6 const params = { tags: { my_tag: 'hello' } };
7
8 const response = ws.connect(url, params, function (socket) {
9 socket.on('open', function open() {
10 console.log('connected');
11 socket.send(Date.now());
12
13 socket.setInterval(function timeout() {
14 socket.ping();
15 console.log('Pinging every 1sec (setInterval test)');
16 }, 1000);
17 });
18
19 socket.on('ping', () => console.log('PING!'));
20 socket.on('pong', () => console.log('PONG!'));
21 socket.on('pong', () => {
22 // Multiple event handlers on the same event
23 console.log('OTHER PONG!');
24 });
25
26 socket.on('close', () => console.log('disconnected'));
27
28 socket.on('error', (e) => {
29 if (e.error() != 'websocket: close sent') {
30 console.log('An unexpected error occured: ', e.error());
31 }
32 });
33
34 socket.setTimeout(function () {
35 console.log('2 seconds passed, closing the socket');
36 socket.close();
37 }, 2000);
38 });
39
40 check(response, { 'status is 101': (r) => r && r.status === 101 });
41}