Skip to content

Commit

Permalink
feat: measure ws performance
Browse files Browse the repository at this point in the history
  • Loading branch information
juanfran committed Feb 21, 2025
1 parent 157b313 commit f191a75
Showing 1 changed file with 167 additions and 99 deletions.
266 changes: 167 additions & 99 deletions apps/api/src/simulate-users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,131 +29,199 @@ const MAX_EMITS = 250;
const PORT = 8000;
const AUTH = '';
const BOARD_ID = '';
const clientData: Record<
string,
{
totalMessages: number;
}
> = {};

console.time('time');

function randomRange(min: number, max: number) {
return Math.random() * (max - min) + min;
}

function createClient(index: number) {
let interval: NodeJS.Timeout;
let emits = 0;
let init = false;
const noteId = uuidv4();
const ownerId = `user_${index}_${Date.now()}`;
const randomInitX = Math.random() * 1000;
const randomInitY = Math.random() * 1000;

const initialX = randomInitX + index * 50;
const initialY = randomInitY;

const ws = io(`ws://localhost:${PORT}`, {
extraHeaders: { Cookie: AUTH },
});

function start() {
interval = setInterval(() => {
const progress = (Date.now() % 4000) / 1000;
const side = Math.floor(progress);
const sideProgress = progress - side;

let x = initialX;
let y = initialY;

switch (side) {
case 0:
x += SQUARE_SIZE * sideProgress;
break;
case 1:
x += SQUARE_SIZE;
y += SQUARE_SIZE * sideProgress;
break;
case 2:
x += SQUARE_SIZE * (1 - sideProgress);
y += SQUARE_SIZE;
break;
case 3:
y += SQUARE_SIZE * (1 - sideProgress);
break;
}

ws.emit('board', [
{
data: {
type: 'note',
id: noteId,
content: {
text: `Client ${index} ${Math.random()}`,
position: { x, y },
color: `#${Math.floor(Math.random() * 16777215).toString(16)}`,
},
},
position: randomRange(0, NUM_CONNECTIONS - 1),
op: 'patch',
},
]);

emits++;

if (emits >= MAX_EMITS) {
clearInterval(interval);
console.log(`Client ${index} finished`);
}
}, STEP_DELAY);
}

ws.on('connect', () => {
console.log(`Client ${index} connected`);

ws.emit('board', [
{
boardId: BOARD_ID,
action: 'join',
},
]);
return new Promise((resolve) => {
const clientId = `user_${index}`;
let interval: NodeJS.Timeout;
let intervalTimeout: NodeJS.Timeout;
let emits = 0;
let init = false;
const noteId = uuidv4();
const ownerId = `user_${index}_${Date.now()}`;
const randomInitX = Math.random() * 1000;
const randomInitY = Math.random() * 1000;
let lastMessage = Date.now();

clientData[clientId] = {
totalMessages: 0,
};

const initialX = randomInitX + index * 50;
const initialY = randomInitY;

const ws = io(`ws://localhost:${PORT}`, {
extraHeaders: { Cookie: AUTH },
});

ws.on('board', (response) => {
if (response && response[0].type === '[Board] State action' && !init) {
init = true;
const close = (reason: string) => {
clearInterval(interval);
clearInterval(intervalTimeout);

resolve({
clientId,
totalMessages: clientData[clientId].totalMessages,
reason,
});
};

function start() {
interval = setInterval(() => {
const progress = (Date.now() % 4000) / 1000;
const side = Math.floor(progress);
const sideProgress = progress - side;

let x = initialX;
let y = initialY;

switch (side) {
case 0:
x += SQUARE_SIZE * sideProgress;
break;
case 1:
x += SQUARE_SIZE;
y += SQUARE_SIZE * sideProgress;
break;
case 2:
x += SQUARE_SIZE * (1 - sideProgress);
y += SQUARE_SIZE;
break;
case 3:
y += SQUARE_SIZE * (1 - sideProgress);
break;
}

ws.emit('board', [
{
data: {
type: 'note',
id: noteId,
content: {
text: '',
votes: [],
emojis: [],
drawing: [],
width: 300,
height: 300,
ownerId: ownerId,
layer: 0,
text: `Client ${index} ${Math.random()}`,
position: { x, y },
color: `#${Math.floor(Math.random() * 16777215).toString(16)}`,
position: { x: initialX, y: initialY },
},
},
op: 'add',
position: randomRange(0, NUM_CONNECTIONS - 1),
op: 'patch',
},
]);

setTimeout(() => {
start();
}, 500);
}
emits++;

if (emits >= MAX_EMITS) {
ws.emit('board', [
{
data: {
type: 'note',
id: noteId,
},
op: 'remove',
},
]);

console.log(`Client ${index} finished`);
clearInterval(interval);
}
}, STEP_DELAY);
}

ws.on('error', (err) => {
console.error(`Error client ${index}:`, err.message);
});

ws.on('disconnect', () => {
clearInterval(interval);
console.log(`Client ${index} disconnected`);
ws.on('connect', () => {
console.log(`Client ${index} connected`);

ws.emit('board', [
{
boardId: BOARD_ID,
action: 'join',
},
]);

intervalTimeout = setInterval(() => {
let timeout = 300;

if (!init) {
timeout = 500;
}

const diff = Date.now() - lastMessage;

if (diff > timeout) {
close(`Client ${index} timeout ${diff}`);
}
}, 100);

ws.on('board', (response) => {
lastMessage = Date.now();
clientData[clientId].totalMessages++;

if (response && response[0].type === '[Board] State action' && !init) {
init = true;

ws.emit('board', [
{
data: {
type: 'note',
id: noteId,
content: {
text: '',
votes: [],
emojis: [],
drawing: [],
width: 300,
height: 300,
ownerId: ownerId,
layer: 0,
color: `#${Math.floor(Math.random() * 16777215).toString(16)}`,
position: { x: initialX, y: initialY },
},
},
op: 'add',
},
]);

setTimeout(() => {
start();
}, 500);
}
});

ws.on('disconnect', () => {
close(`Client ${index} disconnected`);
});
});
});

ws.on('connect_error', (err) => {
console.error(`Error client ${index}:`, err.message);
ws.on('connect_error', (err) => {
console.error(`Error client ${index}:`, err.message);
});
});
}

const clients = [];

for (let i = 0; i < NUM_CONNECTIONS; i++) {
createClient(i);
clients.push(createClient(i));
}

Promise.all(clients).then((results) => {
console.log(results);

console.timeEnd('time');

process.exit(0);
});

0 comments on commit f191a75

Please sign in to comment.