Skip to content

Commit 07c9e57

Browse files
authored
Merge pull request #25 from temporalio/rh-more-stats
More stats on load test dashbord
2 parents f917953 + 69e89dc commit 07c9e57

File tree

5 files changed

+150
-51
lines changed

5 files changed

+150
-51
lines changed

src/lib/server/load-generator/index.ts

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ import { env } from '$env/dynamic/private';
44
class LoadGenerator {
55
private running: boolean = false;
66
private orderInterval: number | null = null;
7-
private pollInterval: number | null = null;
7+
private pollTimeoutID: number | null = null;
88

99
private config = {
1010
ordersPerSecond: 1,
11-
pollFrequency: 500, // How often to poll shipments (ms)
11+
pollFrequency: 500, // How long to wait between shipment polls (ms)
1212
};
1313

1414
public start(config?: Partial<typeof this.config>) {
@@ -21,7 +21,7 @@ class LoadGenerator {
2121

2222
const orderDelay = 1000 / this.config.ordersPerSecond;
2323
this.orderInterval = setInterval(() => this.createOrder(), orderDelay);
24-
this.pollInterval = setInterval(() => this.pollShipments(), this.config.pollFrequency);
24+
this.scheduleNextPoll();
2525

2626
console.log('Load generator started');
2727
}
@@ -43,9 +43,9 @@ class LoadGenerator {
4343
clearInterval(this.orderInterval);
4444
this.orderInterval = null;
4545
}
46-
if (this.pollInterval) {
47-
clearInterval(this.pollInterval);
48-
this.pollInterval = null;
46+
if (this.pollTimeoutID) {
47+
clearInterval(this.pollTimeoutID);
48+
this.pollTimeoutID = null;
4949
}
5050

5151
console.log('Load generator stopped');
@@ -63,33 +63,39 @@ class LoadGenerator {
6363
}
6464
}
6565

66+
private scheduleNextPoll() {
67+
if (!this.running) return;
68+
69+
this.pollTimeoutID = setTimeout(() => {
70+
this.pollShipments()
71+
.catch(error => console.error('Error in pollShipments:', error))
72+
.finally(() => this.scheduleNextPoll());
73+
}, this.config.pollFrequency);
74+
}
75+
6676
private async pollShipments() {
67-
try {
68-
const response = await fetch(`${env.SHIPMENT_API_URL}/shipments/pending`);
69-
const shipments = await response.json();
77+
const response = await fetch(`${env.SHIPMENT_API_URL}/shipments/pending`);
78+
const shipments = await response.json();
7079

71-
for (const shipment of shipments) {
72-
var next = "";
80+
for (const shipment of shipments) {
81+
var next = "";
7382

74-
if (shipment.status === 'booked') {
75-
next = 'dispatched';
76-
} else if (shipment.status === 'dispatched') {
77-
next = 'delivered';
78-
}
83+
if (shipment.status === 'booked') {
84+
next = 'dispatched';
85+
} else if (shipment.status === 'dispatched') {
86+
next = 'delivered';
87+
}
7988

80-
if (next != '') {
81-
try {
82-
await fetch(`${env.SHIPMENT_API_URL}/shipments/${shipment.id}/status`, {
83-
method: 'POST',
84-
body: JSON.stringify({ status: next }),
85-
});
86-
} catch (error) {
87-
console.error('Failed to update shipment status:', error);
88-
}
89+
if (next != '') {
90+
try {
91+
await fetch(`${env.SHIPMENT_API_URL}/shipments/${shipment.id}/status`, {
92+
method: 'POST',
93+
body: JSON.stringify({ status: next }),
94+
});
95+
} catch (error) {
96+
console.error('Failed to update shipment status:', error);
8997
}
9098
}
91-
} catch (error) {
92-
console.error('Failed to poll shipments:', error);
9399
}
94100
}
95101
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { json } from '@sveltejs/kit';
2+
import { env } from '$env/dynamic/private';
3+
4+
export const GET = async () => {
5+
const response = await fetch(`${env.BILLING_API_URL}/charge/stats`);
6+
const { workerCount, completeRate, backlog } = await response.json();
7+
return json({ workerCount, completeRate, backlog });
8+
};

src/routes/api/order/stats/+server.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,7 @@ import { json } from '@sveltejs/kit';
22
import { env } from '$env/dynamic/private';
33

44
export const GET = async () => {
5-
try {
6-
const response = await fetch(`${env.ORDER_API_URL}/orders/stats`);
7-
const { completeRate, backlog } = await response.json();
8-
return json({ completeRate, backlog });
9-
} catch (error) {
10-
console.error('Failed to fetch backlog:', error);
11-
return json(0, { status: 500 });
12-
}
5+
const response = await fetch(`${env.ORDER_API_URL}/orders/stats`);
6+
const { workerCount, completeRate, backlog } = await response.json();
7+
return json({ workerCount, completeRate, backlog });
138
};
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { json } from '@sveltejs/kit';
2+
import { env } from '$env/dynamic/private';
3+
4+
export const GET = async () => {
5+
const response = await fetch(`${env.SHIPMENT_API_URL}/shipments/stats`);
6+
const { workerCount, completeRate, backlog } = await response.json();
7+
return json({ workerCount, completeRate, backlog });
8+
};

src/routes/operator/+page.svelte

Lines changed: 98 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<script lang="ts">
22
import { onMount, onDestroy } from 'svelte';
33
import { Line } from 'svelte-chartjs';
4-
import { goto, invalidateAll } from '$app/navigation';
4+
import { invalidateAll } from '$app/navigation';
55
import {
66
Chart as ChartJS,
77
CategoryScale,
@@ -27,43 +27,105 @@
2727
2828
$: ({ running, config } = data);
2929
30+
let workerCountChartData = {
31+
labels: [] as string[],
32+
datasets: [
33+
{
34+
label: 'Order',
35+
data: [] as number[],
36+
borderColor: 'green',
37+
tension: 0.1
38+
},
39+
{
40+
label: 'Shipment',
41+
data: [] as number[],
42+
borderColor: 'blue',
43+
tension: 0.1
44+
},
45+
{
46+
label: 'Charge',
47+
data: [] as number[],
48+
borderColor: 'orange',
49+
tension: 0.1
50+
}
51+
]
52+
}
53+
3054
let completeChartData = {
31-
labels: [],
55+
labels: [] as string[],
3256
datasets: [
3357
{
34-
label: 'Order Complete RPS',
35-
data: [],
58+
label: 'Order',
59+
data: [] as number[],
3660
borderColor: 'green',
3761
tension: 0.1
3862
},
63+
{
64+
label: 'Shipment',
65+
data: [] as number[],
66+
borderColor: 'blue',
67+
tension: 0.1
68+
},
69+
{
70+
label: 'Charge',
71+
data: [] as number[],
72+
borderColor: 'orange',
73+
tension: 0.1
74+
}
3975
]
4076
};
4177
4278
let backlogChartData = {
43-
labels: [],
79+
labels: [] as string[],
4480
datasets: [
4581
{
46-
label: 'Order Backlog',
47-
data: [],
48-
borderColor: 'red',
82+
label: 'Order',
83+
data: [] as number[],
84+
borderColor: 'green',
4985
tension: 0.1
5086
},
87+
{
88+
label: 'Shipment',
89+
data: [] as number[],
90+
borderColor: 'blue',
91+
tension: 0.1
92+
},
93+
{
94+
label: 'Charge',
95+
data: [] as number[],
96+
borderColor: 'orange',
97+
tension: 0.1
98+
}
5199
]
52100
};
53101
54102
let refreshInterval: number;
55103
56104
const updateChartData = async() => {
57-
const response = await fetch('/api/order/stats');
58-
const { completeRate, backlog } = await response.json();
59-
60105
const now = new Date().toLocaleTimeString();
61106
107+
workerCountChartData.labels = [...workerCountChartData.labels.slice(-20), now];
62108
completeChartData.labels = [...completeChartData.labels.slice(-20), now];
63109
backlogChartData.labels = [...backlogChartData.labels.slice(-20), now];
64-
completeChartData.datasets[0].data = [...completeChartData.datasets[0].data.slice(-20), completeRate];
65-
backlogChartData.datasets[0].data = [...backlogChartData.datasets[0].data.slice(-20), backlog];
66-
chartData = chartData; // trigger reactivity
110+
111+
const responses = await Promise.all([
112+
fetch('/api/order/stats'),
113+
fetch('/api/shipment/stats'),
114+
fetch('/api/charge/stats')
115+
]);
116+
117+
const allStats = await Promise.all(responses.map(response => response.json()));
118+
119+
allStats.forEach((stats, i) => {
120+
let { workerCount, completeRate, backlog } = stats;
121+
workerCountChartData.datasets[i].data = [...workerCountChartData.datasets[i].data.slice(-20), workerCount];
122+
completeChartData.datasets[i].data = [...completeChartData.datasets[i].data.slice(-20), completeRate];
123+
backlogChartData.datasets[i].data = [...backlogChartData.datasets[i].data.slice(-20), backlog];
124+
});
125+
126+
workerCountChartData = workerCountChartData
127+
completeChartData = completeChartData
128+
backlogChartData = backlogChartData
67129
}
68130
69131
onMount(() => {
@@ -113,7 +175,7 @@
113175
</div>
114176
<div class="flex gap-2 w-full">
115177
<div class="w-full p-4 flex flex-col gap-4 bg-white border border-black rounded">
116-
<h3 class="text-xl font-bold">Order Completions</h3>
178+
<h3 class="text-xl font-bold">Completions</h3>
117179
<div class="w-full h-[300px]">
118180
<Line
119181
data={completeChartData}
@@ -130,8 +192,28 @@
130192
/>
131193
</div>
132194
</div>
195+
</div>
196+
<div class="flex gap-2 w-full">
197+
<div class="w-full p-4 flex flex-col gap-4 bg-white border border-black rounded">
198+
<h3 class="text-xl font-bold">Workers</h3>
199+
<div class="w-full h-[300px]">
200+
<Line
201+
data={workerCountChartData}
202+
options={{
203+
responsive: true,
204+
maintainAspectRatio: false,
205+
animation: false,
206+
scales: {
207+
y: {
208+
beginAtZero: true
209+
}
210+
}
211+
}}
212+
/>
213+
</div>
214+
</div>
133215
<div class="w-full p-4 flex flex-col gap-4 bg-white border border-black rounded">
134-
<h3 class="text-xl font-bold">Order Backlog</h3>
216+
<h3 class="text-xl font-bold">Backlog</h3>
135217
<div class="w-full h-[300px]">
136218
<Line
137219
data={backlogChartData}

0 commit comments

Comments
 (0)