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