66 lines
2.5 KiB
JavaScript
66 lines
2.5 KiB
JavaScript
const canvas = document.getElementById('arch-canvas');
|
|
const ctx = canvas.getContext('2d');
|
|
const state = {
|
|
users: 120,
|
|
databaseLoad: 45,
|
|
servers: [
|
|
{ name: 'web-1', healthy: true, load: 34 },
|
|
{ name: 'web-2', healthy: true, load: 28 },
|
|
{ name: 'web-3', healthy: true, load: 31 },
|
|
],
|
|
};
|
|
|
|
function box(x, y, width, height, fill, stroke, label) {
|
|
ctx.fillStyle = fill;
|
|
ctx.strokeStyle = stroke;
|
|
ctx.beginPath();
|
|
ctx.roundRect(x, y, width, height, 8);
|
|
ctx.fill();
|
|
ctx.stroke();
|
|
ctx.fillStyle = '#102a43';
|
|
ctx.fillText(label, x + 12, y + height / 2 + 5);
|
|
}
|
|
|
|
function draw() {
|
|
const healthy = state.servers.filter((server) => server.healthy);
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
ctx.fillStyle = '#f8fafc';
|
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
ctx.font = '14px Arial';
|
|
ctx.fillStyle = '#102a43';
|
|
ctx.fillText(`${state.users} simulated users`, 30, 36);
|
|
box(240, 95, 110, 64, '#dbeafe', '#2563eb', 'Load balancer');
|
|
state.servers.forEach((server, index) => {
|
|
const x = 440;
|
|
const y = 40 + index * 68;
|
|
server.load = server.healthy && healthy.length ? Math.min(100, Math.round(state.users / healthy.length / 6)) : 0;
|
|
ctx.strokeStyle = '#9fb3c8';
|
|
ctx.beginPath();
|
|
ctx.moveTo(350, 127);
|
|
ctx.lineTo(x, y + 24);
|
|
ctx.stroke();
|
|
box(x, y, 120, 48, server.healthy ? '#e8fff1' : '#ffe8e8', server.healthy ? '#2f855a' : '#c53030', `${server.name} ${server.healthy ? server.load + '%' : 'down'}`);
|
|
});
|
|
state.databaseLoad = Math.min(100, state.databaseLoad + state.users / 400);
|
|
ctx.strokeStyle = '#9fb3c8';
|
|
ctx.beginPath();
|
|
ctx.moveTo(560, 127);
|
|
ctx.lineTo(620, 127);
|
|
ctx.stroke();
|
|
box(620, 95, 72, 64, state.databaseLoad > 80 ? '#fff5d6' : '#edf2f7', state.databaseLoad > 80 ? '#d69e2e' : '#52606d', `DB ${Math.round(state.databaseLoad)}%`);
|
|
document.getElementById('arch-status').textContent = healthy.length ? `Traffic split across ${healthy.length} healthy web nodes.` : 'All web nodes are down. Auto-scaling is needed.';
|
|
}
|
|
|
|
document.getElementById('add-users').addEventListener('click', () => { state.users += 220; state.databaseLoad += 10; draw(); });
|
|
document.getElementById('server-crash').addEventListener('click', () => {
|
|
const server = state.servers.find((item) => item.healthy);
|
|
if (server) server.healthy = false;
|
|
draw();
|
|
});
|
|
document.getElementById('auto-scale').addEventListener('click', () => {
|
|
state.servers.push({ name: `web-${state.servers.length + 1}`, healthy: true, load: 10 });
|
|
state.databaseLoad = Math.max(35, state.databaseLoad - 20);
|
|
draw();
|
|
});
|
|
draw();
|