koa-classic-server 1.2.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,354 @@
1
+
2
+ > koa-classic-server@1.2.0 test:performance
3
+ > jest __tests__/performance.test.js --runInBand
4
+
5
+ console.log
6
+
7
+ šŸ“Š Small File (1KB) Benchmark:
8
+
9
+ at Object.log (__tests__/performance.test.js:90:21)
10
+
11
+ console.log
12
+ Average: 2.93ms
13
+
14
+ at Object.log (__tests__/performance.test.js:91:21)
15
+
16
+ console.log
17
+ Median: 2.48ms
18
+
19
+ at Object.log (__tests__/performance.test.js:92:21)
20
+
21
+ console.log
22
+ Min: 1.90ms
23
+
24
+ at Object.log (__tests__/performance.test.js:93:21)
25
+
26
+ console.log
27
+ Max: 25.14ms
28
+
29
+ at Object.log (__tests__/performance.test.js:94:21)
30
+
31
+ console.log
32
+
33
+ šŸ“Š Medium File (100KB) Benchmark:
34
+
35
+ at Object.log (__tests__/performance.test.js:109:21)
36
+
37
+ console.log
38
+ Average: 3.13ms
39
+
40
+ at Object.log (__tests__/performance.test.js:110:21)
41
+
42
+ console.log
43
+ Median: 3.15ms
44
+
45
+ at Object.log (__tests__/performance.test.js:111:21)
46
+
47
+ console.log
48
+ Min: 2.31ms
49
+
50
+ at Object.log (__tests__/performance.test.js:112:21)
51
+
52
+ console.log
53
+ Max: 4.11ms
54
+
55
+ at Object.log (__tests__/performance.test.js:113:21)
56
+
57
+ console.log
58
+
59
+ šŸ“Š Large File (1MB) Benchmark:
60
+
61
+ at Object.log (__tests__/performance.test.js:128:21)
62
+
63
+ console.log
64
+ Average: 8.76ms
65
+
66
+ at Object.log (__tests__/performance.test.js:129:21)
67
+
68
+ console.log
69
+ Median: 9.85ms
70
+
71
+ at Object.log (__tests__/performance.test.js:130:21)
72
+
73
+ console.log
74
+ Min: 5.79ms
75
+
76
+ at Object.log (__tests__/performance.test.js:131:21)
77
+
78
+ console.log
79
+ Max: 11.72ms
80
+
81
+ at Object.log (__tests__/performance.test.js:132:21)
82
+
83
+ console.log
84
+
85
+ šŸ“Š Small Directory (100 files) Benchmark:
86
+
87
+ at Object.log (__tests__/performance.test.js:150:21)
88
+
89
+ console.log
90
+ Average: 2.68ms
91
+
92
+ at Object.log (__tests__/performance.test.js:151:21)
93
+
94
+ console.log
95
+ Median: 2.53ms
96
+
97
+ at Object.log (__tests__/performance.test.js:152:21)
98
+
99
+ console.log
100
+ Min: 2.22ms
101
+
102
+ at Object.log (__tests__/performance.test.js:153:21)
103
+
104
+ console.log
105
+ Max: 4.79ms
106
+
107
+ at Object.log (__tests__/performance.test.js:154:21)
108
+
109
+ console.log
110
+
111
+ šŸ“Š Large Directory (1,000 files) Benchmark:
112
+
113
+ at Object.log (__tests__/performance.test.js:168:21)
114
+
115
+ console.log
116
+ Average: 9.49ms
117
+
118
+ at Object.log (__tests__/performance.test.js:169:21)
119
+
120
+ console.log
121
+ Median: 9.16ms
122
+
123
+ at Object.log (__tests__/performance.test.js:170:21)
124
+
125
+ console.log
126
+ Min: 8.20ms
127
+
128
+ at Object.log (__tests__/performance.test.js:171:21)
129
+
130
+ console.log
131
+ Max: 11.49ms
132
+
133
+ at Object.log (__tests__/performance.test.js:172:21)
134
+
135
+ console.log
136
+ āš ļø WARNING: This will be MUCH faster after async optimization
137
+
138
+ at Object.log (__tests__/performance.test.js:175:21)
139
+
140
+ console.log
141
+
142
+ šŸ“Š Very Large Directory (10,000 files) Benchmark:
143
+
144
+ at Object.log (__tests__/performance.test.js:189:21)
145
+
146
+ console.log
147
+ Average: 90.06ms
148
+
149
+ at Object.log (__tests__/performance.test.js:190:21)
150
+
151
+ console.log
152
+ Median: 90.14ms
153
+
154
+ at Object.log (__tests__/performance.test.js:191:21)
155
+
156
+ console.log
157
+ Min: 87.00ms
158
+
159
+ at Object.log (__tests__/performance.test.js:192:21)
160
+
161
+ console.log
162
+ Max: 93.29ms
163
+
164
+ at Object.log (__tests__/performance.test.js:193:21)
165
+
166
+ console.log
167
+ āš ļø WARNING: Event loop BLOCKED during this operation!
168
+
169
+ at Object.log (__tests__/performance.test.js:194:21)
170
+
171
+ console.log
172
+ āš ļø Expected to drop to ~27.02ms after optimization
173
+
174
+ at Object.log (__tests__/performance.test.js:195:21)
175
+
176
+ console.log
177
+
178
+ šŸ“Š 10 Concurrent Small Files:
179
+
180
+ at Object.log (__tests__/performance.test.js:212:21)
181
+
182
+ console.log
183
+ Total time: 14.35ms
184
+
185
+ at Object.log (__tests__/performance.test.js:213:21)
186
+
187
+ console.log
188
+ Avg per request: 1.43ms
189
+
190
+ at Object.log (__tests__/performance.test.js:214:21)
191
+
192
+ console.log
193
+
194
+ šŸ“Š 5 Concurrent Directory Listings (100 files):
195
+
196
+ at Object.log (__tests__/performance.test.js:231:21)
197
+
198
+ console.log
199
+ Total time: 7.26ms
200
+
201
+ at Object.log (__tests__/performance.test.js:232:21)
202
+
203
+ console.log
204
+ Avg per request: 1.45ms
205
+
206
+ at Object.log (__tests__/performance.test.js:233:21)
207
+
208
+ console.log
209
+ āš ļø With current sync code, these run SEQUENTIALLY
210
+
211
+ at Object.log (__tests__/performance.test.js:234:21)
212
+
213
+ console.log
214
+ āš ļø After async optimization, will run in PARALLEL
215
+
216
+ at Object.log (__tests__/performance.test.js:235:21)
217
+
218
+ console.log
219
+
220
+ šŸ“Š 404 Not Found Benchmark:
221
+
222
+ at Object.log (__tests__/performance.test.js:252:21)
223
+
224
+ console.log
225
+ Average: 1.53ms
226
+
227
+ at Object.log (__tests__/performance.test.js:253:21)
228
+
229
+ console.log
230
+ Median: 1.43ms
231
+
232
+ at Object.log (__tests__/performance.test.js:254:21)
233
+
234
+ console.log
235
+ Min: 1.24ms
236
+
237
+ at Object.log (__tests__/performance.test.js:255:21)
238
+
239
+ console.log
240
+ Max: 3.80ms
241
+
242
+ at Object.log (__tests__/performance.test.js:256:21)
243
+
244
+ console.log
245
+
246
+ šŸ“Š Memory Usage (10,000 files directory):
247
+
248
+ at Object.log (__tests__/performance.test.js:278:21)
249
+
250
+ console.log
251
+ Heap used increase: 0.96 MB
252
+
253
+ at Object.log (__tests__/performance.test.js:279:21)
254
+
255
+ console.log
256
+ External increase: 2.54 MB
257
+
258
+ at Object.log (__tests__/performance.test.js:280:21)
259
+
260
+ console.log
261
+ Response size: 1.29 MB
262
+
263
+ at Object.log (__tests__/performance.test.js:281:21)
264
+
265
+ console.log
266
+ āš ļø Expected to reduce by ~30-40% after optimization
267
+
268
+ at Object.log (__tests__/performance.test.js:282:21)
269
+
270
+ console.log
271
+
272
+ ======================================================================
273
+
274
+ at Object.log (__tests__/performance.test.js:289:13)
275
+
276
+ console.log
277
+ šŸ“‹ BASELINE BENCHMARK SUMMARY
278
+
279
+ at Object.log (__tests__/performance.test.js:290:13)
280
+
281
+ console.log
282
+ ======================================================================
283
+
284
+ at Object.log (__tests__/performance.test.js:291:13)
285
+
286
+ console.log
287
+
288
+ These results represent the CURRENT performance (v1.2.0)
289
+
290
+ at Object.log (__tests__/performance.test.js:292:13)
291
+
292
+ console.log
293
+ After implementing optimizations, run this test again to see improvements.
294
+
295
+ at Object.log (__tests__/performance.test.js:293:13)
296
+
297
+ console.log
298
+ Expected improvements after optimization:
299
+
300
+ at Object.log (__tests__/performance.test.js:294:13)
301
+
302
+ console.log
303
+ āœ“ Small files: 10-20% faster (async operations)
304
+
305
+ at Object.log (__tests__/performance.test.js:295:13)
306
+
307
+ console.log
308
+ āœ“ Large directories: 50-70% faster (async + array join)
309
+
310
+ at Object.log (__tests__/performance.test.js:296:13)
311
+
312
+ console.log
313
+ āœ“ Concurrent requests: 5-10x faster (non-blocking event loop)
314
+
315
+ at Object.log (__tests__/performance.test.js:297:13)
316
+
317
+ console.log
318
+ āœ“ Memory usage: 30-40% reduction (array join vs concatenation)
319
+
320
+ at Object.log (__tests__/performance.test.js:298:13)
321
+
322
+ console.log
323
+ āœ“ With HTTP caching: 80-95% faster (304 responses)
324
+
325
+ at Object.log (__tests__/performance.test.js:299:13)
326
+
327
+ console.log
328
+ ======================================================================
329
+
330
+ at Object.log (__tests__/performance.test.js:300:13)
331
+
332
+ PASS __tests__/performance.test.js
333
+ Performance Benchmarks - BASELINE (v1.2.0)
334
+ File Serving Performance
335
+ āœ“ Benchmark: Small file (1KB) - 100 iterations (322 ms)
336
+ āœ“ Benchmark: Medium file (100KB) - 50 iterations (160 ms)
337
+ āœ“ Benchmark: Large file (1MB) - 20 iterations (178 ms)
338
+ Directory Listing Performance
339
+ āœ“ Benchmark: Small directory (100 files) - 50 iterations (136 ms)
340
+ āœ“ Benchmark: Large directory (1,000 files) - 20 iterations (192 ms)
341
+ āœ“ Benchmark: Very large directory (10,000 files) - 5 iterations (454 ms)
342
+ Concurrent Request Performance
343
+ āœ“ Benchmark: 10 concurrent small file requests (17 ms)
344
+ āœ“ Benchmark: 5 concurrent directory listings (100 files each) (9 ms)
345
+ 404 Not Found Performance
346
+ āœ“ Benchmark: Non-existent file - 50 iterations (79 ms)
347
+ Memory Usage (Informational)
348
+ āœ“ Memory usage during large directory listing (90 ms)
349
+
350
+ Test Suites: 1 passed, 1 total
351
+ Tests: 10 passed, 10 total
352
+ Snapshots: 0 total
353
+ Time: 2.781 s, estimated 4 s
354
+ Ran all test suites matching /__tests__\/performance.test.js/i.
package/benchmark.js ADDED
@@ -0,0 +1,239 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * HTTP Load Testing Benchmark using autocannon
5
+ *
6
+ * This script performs realistic load testing to measure:
7
+ * - Requests per second
8
+ * - Latency (avg, p50, p99)
9
+ * - Throughput
10
+ *
11
+ * Usage:
12
+ * node benchmark.js
13
+ * node benchmark.js --save baseline.json
14
+ *
15
+ * Compare before/after:
16
+ * node benchmark.js --save before.json
17
+ * # ... apply optimizations ...
18
+ * node benchmark.js --save after.json --compare before.json
19
+ */
20
+
21
+ const autocannon = require('autocannon');
22
+ const Koa = require('koa');
23
+ const koaClassicServer = require('./index.cjs');
24
+ const path = require('path');
25
+ const fs = require('fs');
26
+
27
+ const BENCHMARK_DIR = path.join(__dirname, 'benchmark-data');
28
+
29
+ // Check if benchmark data exists
30
+ if (!fs.existsSync(BENCHMARK_DIR)) {
31
+ console.error('\nāŒ Benchmark data not found!');
32
+ console.error('Please run: node scripts/setup-benchmark.js\n');
33
+ process.exit(1);
34
+ }
35
+
36
+ // Parse command line arguments
37
+ const args = process.argv.slice(2);
38
+ const saveFile = args.includes('--save') ? args[args.indexOf('--save') + 1] : null;
39
+ const compareFile = args.includes('--compare') ? args[args.indexOf('--compare') + 1] : null;
40
+
41
+ console.log('šŸš€ Starting koa-classic-server benchmark...\n');
42
+
43
+ // Start server
44
+ const app = new Koa();
45
+ app.use(koaClassicServer(BENCHMARK_DIR));
46
+ const server = app.listen(0); // Random available port
47
+
48
+ const port = server.address().port;
49
+ console.log(`Server running on http://localhost:${port}\n`);
50
+
51
+ // Define benchmark scenarios
52
+ const scenarios = [
53
+ {
54
+ name: 'Small file (1KB)',
55
+ url: `http://localhost:${port}/small-files/file-1.txt`,
56
+ duration: 10,
57
+ connections: 10
58
+ },
59
+ {
60
+ name: 'Medium file (100KB)',
61
+ url: `http://localhost:${port}/medium-files/file-1.txt`,
62
+ duration: 10,
63
+ connections: 10
64
+ },
65
+ {
66
+ name: 'Large file (1MB)',
67
+ url: `http://localhost:${port}/large-files/file-1.txt`,
68
+ duration: 10,
69
+ connections: 10
70
+ },
71
+ {
72
+ name: 'Directory listing (100 files)',
73
+ url: `http://localhost:${port}/small-files/`,
74
+ duration: 10,
75
+ connections: 10
76
+ },
77
+ {
78
+ name: 'Directory listing (1,000 files)',
79
+ url: `http://localhost:${port}/large-directory/`,
80
+ duration: 10,
81
+ connections: 5
82
+ },
83
+ {
84
+ name: 'HTML file',
85
+ url: `http://localhost:${port}/test.html`,
86
+ duration: 10,
87
+ connections: 10
88
+ },
89
+ {
90
+ name: '404 Not Found',
91
+ url: `http://localhost:${port}/does-not-exist.txt`,
92
+ duration: 10,
93
+ connections: 10
94
+ }
95
+ ];
96
+
97
+ // Run benchmarks sequentially
98
+ async function runBenchmarks() {
99
+ const results = {};
100
+
101
+ for (const scenario of scenarios) {
102
+ console.log('─'.repeat(70));
103
+ console.log(`šŸ“Š Benchmarking: ${scenario.name}`);
104
+ console.log('─'.repeat(70));
105
+
106
+ const result = await runBenchmark(scenario);
107
+ results[scenario.name] = result;
108
+
109
+ // Wait a bit between tests
110
+ await sleep(2000);
111
+ }
112
+
113
+ return results;
114
+ }
115
+
116
+ function runBenchmark(scenario) {
117
+ return new Promise((resolve, reject) => {
118
+ const instance = autocannon({
119
+ url: scenario.url,
120
+ connections: scenario.connections,
121
+ duration: scenario.duration,
122
+ pipelining: 1,
123
+ }, (err, result) => {
124
+ if (err) {
125
+ reject(err);
126
+ } else {
127
+ printResults(result, scenario.name);
128
+ resolve(formatResults(result, scenario.name));
129
+ }
130
+ });
131
+
132
+ autocannon.track(instance, { renderProgressBar: true });
133
+ });
134
+ }
135
+
136
+ function printResults(result, name) {
137
+ console.log(`\nāœ“ ${name} - Results:`);
138
+ console.log(` Requests/sec: ${result.requests.average.toFixed(2)}`);
139
+ console.log(` Latency (avg): ${result.latency.mean.toFixed(2)}ms`);
140
+ console.log(` Latency (p50): ${result.latency.p50.toFixed(2)}ms`);
141
+ console.log(` Latency (p99): ${result.latency.p99.toFixed(2)}ms`);
142
+ console.log(` Throughput: ${(result.throughput.average / 1024 / 1024).toFixed(2)} MB/sec`);
143
+ console.log(` Total requests: ${result.requests.total}`);
144
+ console.log('');
145
+ }
146
+
147
+ function formatResults(result, name) {
148
+ return {
149
+ name,
150
+ requestsPerSecond: result.requests.average,
151
+ latency: {
152
+ mean: result.latency.mean,
153
+ p50: result.latency.p50,
154
+ p75: result.latency.p75,
155
+ p90: result.latency.p90,
156
+ p99: result.latency.p99,
157
+ p999: result.latency.p999
158
+ },
159
+ throughput: result.throughput.average,
160
+ totalRequests: result.requests.total,
161
+ errors: result.errors
162
+ };
163
+ }
164
+
165
+ function sleep(ms) {
166
+ return new Promise(resolve => setTimeout(resolve, ms));
167
+ }
168
+
169
+ // Main execution
170
+ runBenchmarks()
171
+ .then(results => {
172
+ console.log('='.repeat(70));
173
+ console.log('šŸ“‹ BENCHMARK SUMMARY');
174
+ console.log('='.repeat(70));
175
+ console.log('');
176
+
177
+ // Summary table
178
+ console.log('Scenario | Req/sec | Latency (avg) | Throughput');
179
+ console.log('----------------------------------|---------|---------------|-------------');
180
+
181
+ Object.values(results).forEach(result => {
182
+ const name = result.name.padEnd(33);
183
+ const reqSec = result.requestsPerSecond.toFixed(0).padStart(7);
184
+ const latency = `${result.latency.mean.toFixed(2)}ms`.padStart(13);
185
+ const throughput = `${(result.throughput / 1024 / 1024).toFixed(2)} MB/s`.padStart(11);
186
+ console.log(`${name} | ${reqSec} | ${latency} | ${throughput}`);
187
+ });
188
+
189
+ console.log('');
190
+ console.log('='.repeat(70));
191
+
192
+ // Save results if requested
193
+ if (saveFile) {
194
+ const data = {
195
+ timestamp: new Date().toISOString(),
196
+ version: require('./package.json').version,
197
+ results
198
+ };
199
+ fs.writeFileSync(saveFile, JSON.stringify(data, null, 2));
200
+ console.log(`\nāœ“ Results saved to: ${saveFile}`);
201
+ }
202
+
203
+ // Compare with previous results if requested
204
+ if (compareFile && fs.existsSync(compareFile)) {
205
+ const previous = JSON.parse(fs.readFileSync(compareFile, 'utf8'));
206
+ console.log('\nšŸ“Š COMPARISON WITH PREVIOUS RESULTS');
207
+ console.log('='.repeat(70));
208
+
209
+ Object.keys(results).forEach(key => {
210
+ const current = results[key];
211
+ const prev = previous.results[key];
212
+
213
+ if (prev) {
214
+ const reqDiff = ((current.requestsPerSecond - prev.requestsPerSecond) / prev.requestsPerSecond * 100);
215
+ const latDiff = ((current.latency.mean - prev.latency.mean) / prev.latency.mean * 100);
216
+
217
+ console.log(`\n${key}:`);
218
+ console.log(` Requests/sec: ${prev.requestsPerSecond.toFixed(2)} → ${current.requestsPerSecond.toFixed(2)} (${reqDiff > 0 ? '+' : ''}${reqDiff.toFixed(1)}%)`);
219
+ console.log(` Latency: ${prev.latency.mean.toFixed(2)}ms → ${current.latency.mean.toFixed(2)}ms (${latDiff > 0 ? '+' : ''}${latDiff.toFixed(1)}%)`);
220
+
221
+ if (reqDiff > 10) {
222
+ console.log(` āœ… Significant improvement!`);
223
+ } else if (reqDiff < -10) {
224
+ console.log(` āš ļø Performance regression!`);
225
+ }
226
+ }
227
+ });
228
+
229
+ console.log('\n' + '='.repeat(70));
230
+ }
231
+
232
+ server.close();
233
+ console.log('\nāœ“ Benchmark complete!\n');
234
+ })
235
+ .catch(err => {
236
+ console.error('āŒ Benchmark failed:', err);
237
+ server.close();
238
+ process.exit(1);
239
+ });