Hi everyone,
I’m currently testing a WebSocket connection using the experimental xk6-websockets
API (I also tried using k6/ws
).
My k6 version:
k6 v0.45.1 ((devel), go1.21.1, windows/amd64)
Extensions:
github.com/grafana/xk6-output-influxdb v0.4.1, xk6-influxdb [output]
Built using:
go install go.k6.io/xk6/cmd/xk6@latest
xk6 build --with github.com/grafana/xk6-output-influxdb
I also tested using the default k6 binary: k6 v0.46.0 (2023-08-14T13:23:26+0000/v0.46.0-0-gcbd9e9ad, go1.20.7, windows/amd64)
Code
Here is some example code for what I’m trying to achieve:
Test Setup + Options
import { Options } from 'k6/options';
import ws from 'k6/ws';
import { WebSocket } from 'k6/experimental/websockets';
export const options: Options = {
scenarios: {
example: {
executor: 'ramping-vus',
startVUs: 0,
stages: [
{ duration: '10s', target: 10 },
],
gracefulStop: '5s',
exec: 'test'
}
}
};
I have also tried to add a second stage { duration: '5s', target: 0}
with a gracefulRampDown
for 5s, this did not work either.
k6/ws Test
export const test = () => {
const headers: Record<string, string> = { "Sec-Websocket-Protocol": "graphql-transport-ws" };
ws.connect("ws://my.example.com/graphql", {
headers
}, (socket) => {
socket.on('open', () => {
console.log('open');
socket.send(
JSON.stringify({
type: "connection_init",
payload: {},
})
);
});
socket.on('message', () => {
console.log('message');
});
socket.on('error', (ev) => {
console.log('error:', JSON.stringify(ev));
});
socket.on('close', () => {
console.log('closed');
})
});
};
xk6-websockets Test
export const test2 = () => {
const headers: Record<string, string> = { "Sec-Websocket-Protocol": "graphql-transport-ws" };
const socket = new WebSocket("ws://my.example.com/graphql", null, {
headers
});
socket.onopen = () => {
console.log('open!');
socket.send(
JSON.stringify({
type: "connection_init",
payload: {},
})
);
};
socket.onmessage = (ev) => {
console.log('message');
};
socket.onerror = (ev) => {
console.log('error:', JSON.stringify(ev));
};
socket.onclose = () => {
console.log('closed');
};
};
Issue
As you can see above, I’m testing a GraphQL API (I excluded the queries and subscriptions from the test, as they are not relevant here). My problem is that these session run infinitely (which is intended per se, I want to keep a few subscriptions open while executing other scenarios; this simulates the actual application, which also has a few infinite websockets opened).
I already saw in this post that people solved this with a maximum session length, which is shorter than the gracefulShutDown
time. However, I intentionally want these sessions to not have a maximum length and only to close when the VU is being shut or ramped down. This leads to all my iterations being interrupted:
Question
As already mentioned, I know that the common solution for this is to simply limit the session duration. However, I do wonder whether there is some kind of event system (or similar) which allows to be notified when the gracleful rampdown/shutdown should happen so the virtual user can “clean up” to avoid being forcefully shut down (here: close the WebSocket connection).
Here’s what I already did:
- I looked up the issue in the forum and on Stack Overflow. All posts had similar solutions to the post linked above.
- I searched the documentation for Web Sockets and Event Handling. I couldn’t find anything regarding events, and all Web Socket examples close the connection immediatly.
- I checked the repositories for k6 and the xk6-websockets extension, I couldn’t find any related issues or something interesting on the roadmap.
I’m aware that there might not be a fitting solution for my issue (at the moment), but since I didn’t find this question anywhere else, I thought that it couldn’t hurt to ask . Thanks in advance for any help or suggestions!