/
benchmark.js
141 lines (111 loc) · 3.38 KB
/
benchmark.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// Build k6 with xk6-cable like this:
// xk6 build v0.38.3 --with github.com/anycable/xk6-cable@v0.3.0
import { check, sleep, fail } from "k6";
import cable from "k6/x/cable";
import { randomIntBetween } from "https://jslib.k6.io/k6-utils/1.1.0/index.js";
const rampingOptions = {
scenarios: {
default: {
executor: "ramping-vus",
startVUs: 100,
stages: [
{ duration: "20s", target: 300 },
{ duration: "20s", target: 500 },
{ duration: "30s", target: 1000 },
{ duration: "30s", target: 1300 },
{ duration: "30s", target: 1500 },
{ duration: "50s", target: 1500 },
{ duration: "60s", target: 0 },
],
gracefulStop: "5m",
gracefulRampDown: "5m",
},
},
};
export const options = __ENV.SKIP_OPTIONS ? {} : rampingOptions;
import { Trend, Counter } from "k6/metrics";
let rttTrend = new Trend("rtt", true);
let broadcastTrend = new Trend("broadcast_duration", true);
let broadcastsSent = new Counter("broadcasts_sent");
let broadcastsRcvd = new Counter("broadcasts_rcvd");
let acksRcvd = new Counter("acks_rcvd");
// Load ENV from .env
function loadDotEnv() {
try {
let dotenv = open("./.env");
dotenv.split(/[\n\r]/m).forEach((line) => {
// Ignore comments
if (line[0] === "#") return;
let parts = line.split("=", 2);
__ENV[parts[0]] = parts[1];
});
} catch (_err) {}
}
loadDotEnv();
let config = __ENV;
config.URL = config.URL || "ws://localhost:8080/cable";
let url = config.URL;
let channelName = config.CHANNEL_ID || "BenchmarkChannel";
let sendersRatio = parseFloat(config.SENDERS_RATIO || "0.2") || 1;
let sendersMod = (1 / sendersRatio) | 0;
let sender = __VU % sendersMod == 0;
let sendingRate = parseFloat(config.SENDING_RATE || "0.2");
let iterations = (config.N || "100") | 0;
export default function () {
let cableOptions = {
receiveTimeoutMs: 15000,
};
// Prevent from creating a lot of connections at once
sleep(randomIntBetween(2, 10) / 5);
let client = cable.connect(url, cableOptions);
if (
!check(client, {
"successful connection": (obj) => obj,
})
) {
// Cooldown
sleep(randomIntBetween(5, 10) / 5);
fail("connection failed");
}
let channel = client.subscribe(channelName);
if (
!check(channel, {
"successful subscription": (obj) => obj,
})
) {
// Cooldown
sleep(randomIntBetween(5, 10) / 5);
fail("failed to subscribe");
}
for (let i = 0; ; i++) {
// Sampling
if (sender && randomIntBetween(1, 10) / 10 <= sendingRate) {
let start = Date.now();
broadcastsSent.add(1);
// Create message via cable instead of a form
channel.perform("broadcast", {
ts: start,
content: `hello from ${__VU} numero ${i + 1}`,
});
}
sleep(randomIntBetween(5, 10) / 100);
let incoming = channel.receiveAll(1);
for (let message of incoming) {
let received = message.__timestamp__ || Date.now();
if (message.action == "broadcastResult") {
acksRcvd.add(1);
let ts = message.ts;
rttTrend.add(received - ts);
}
if (message.action == "broadcast") {
broadcastsRcvd.add(1);
let ts = message.ts;
broadcastTrend.add(received - ts);
}
}
sleep(randomIntBetween(5, 10) / 10);
if (i > iterations) break;
}
sleep(randomIntBetween(5, 10) / 10);
client.disconnect();
}