Skip to content

Commit 0bef43f

Browse files
committed
refactor
1 parent bb74681 commit 0bef43f

File tree

2 files changed

+124
-36
lines changed

2 files changed

+124
-36
lines changed

benchmark/db-proxy.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
* This helps make benchmark measurements more stable by simulating network conditions
44
*/
55

6+
/* eslint-disable no-console */
7+
68
const net = require('net');
79

810
const PROXY_PORT = parseInt(process.env.PROXY_PORT || '27018', 10);
@@ -52,8 +54,7 @@ const server = net.createServer((clientSocket) => {
5254
});
5355

5456
server.listen(PROXY_PORT, () => {
55-
console.log(`MongoDB proxy listening on port ${PROXY_PORT}`);
56-
console.log(`Forwarding to ${TARGET_HOST}:${TARGET_PORT} with ${LATENCY_MS}ms latency`);
57+
console.log(`MongoDB proxy listening on port ${PROXY_PORT} forwarding to ${TARGET_PORT} with ${LATENCY_MS}ms latency`);
5758
});
5859

5960
process.on('SIGTERM', () => {

benchmark/performance.js

Lines changed: 121 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,35 @@ const ITERATIONS = parseInt(process.env.BENCHMARK_ITERATIONS || '10000', 10);
2424
// Parse Server instance
2525
let parseServer;
2626
let mongoClient;
27+
let proxyProcess;
28+
let proxyServerCleanup;
29+
30+
/**
31+
* Start MongoDB proxy with artificial latency
32+
*/
33+
async function startProxy() {
34+
const { spawn } = require('child_process');
35+
36+
proxyProcess = spawn('node', ['benchmark/db-proxy.js'], {
37+
env: { ...process.env, PROXY_PORT: '27018', TARGET_PORT: '27017', LATENCY_MS: '10000' },
38+
stdio: 'inherit',
39+
});
40+
41+
// Wait for proxy to start
42+
await new Promise(resolve => setTimeout(resolve, 2000));
43+
console.log('MongoDB proxy started on port 27018 with 10ms latency');
44+
}
45+
46+
/**
47+
* Stop MongoDB proxy
48+
*/
49+
async function stopProxy() {
50+
if (proxyProcess) {
51+
proxyProcess.kill();
52+
await new Promise(resolve => setTimeout(resolve, 500));
53+
console.log('MongoDB proxy stopped');
54+
}
55+
}
2756

2857
/**
2958
* Initialize Parse Server for benchmarking
@@ -86,6 +115,66 @@ async function cleanupDatabase() {
86115
}
87116
}
88117

118+
/**
119+
* Reset Parse SDK to use the default server
120+
*/
121+
function resetParseServer() {
122+
Parse.serverURL = SERVER_URL;
123+
}
124+
125+
/**
126+
* Start a Parse Server instance using the DB proxy for latency simulation
127+
* Stores cleanup function globally for later use
128+
*/
129+
async function useProxyServer() {
130+
const express = require('express');
131+
const { default: ParseServer } = require('../lib/index.js');
132+
133+
// Create a new Parse Server instance using the proxy
134+
const app = express();
135+
const proxyParseServer = new ParseServer({
136+
databaseURI: 'mongodb://localhost:27018/parse_benchmark_test',
137+
appId: APP_ID,
138+
masterKey: MASTER_KEY,
139+
serverURL: 'http://localhost:1338/parse',
140+
silent: true,
141+
allowClientClassCreation: true,
142+
logLevel: 'error',
143+
verbose: false,
144+
});
145+
146+
app.use('/parse', proxyParseServer.app);
147+
148+
const server = await new Promise((resolve, reject) => {
149+
const s = app.listen(1338, (err) => {
150+
if (err) {
151+
reject(err);
152+
} else {
153+
resolve(s);
154+
}
155+
});
156+
});
157+
158+
// Configure Parse SDK to use the proxy server
159+
Parse.serverURL = 'http://localhost:1338/parse';
160+
161+
// Store cleanup function globally
162+
proxyServerCleanup = async () => {
163+
server.close();
164+
await new Promise(resolve => setTimeout(resolve, 500));
165+
proxyServerCleanup = null;
166+
};
167+
}
168+
169+
/**
170+
* Clean up proxy server if it's running
171+
*/
172+
async function cleanupProxyServer() {
173+
if (proxyServerCleanup) {
174+
await proxyServerCleanup();
175+
}
176+
}
177+
89178
/**
90179
* Measure average time for an async operation over multiple iterations
91180
* Uses warmup iterations, median metric, and outlier filtering for robustness
@@ -295,8 +384,12 @@ async function benchmarkUserLogin() {
295384

296385
/**
297386
* Benchmark: Query with Include (Parallel Include Pointers)
387+
* This test uses the TCP proxy (port 27018) to simulate 10ms database latency for more realistic measurements
298388
*/
299389
async function benchmarkQueryWithInclude() {
390+
// Start proxy server
391+
await useProxyServer();
392+
300393
// Setup: Create nested object hierarchy
301394
const Level2Class = Parse.Object.extend('Level2');
302395
const Level1Class = Parse.Object.extend('Level1');
@@ -332,11 +425,13 @@ async function benchmarkQueryWithInclude() {
332425
}
333426
await Parse.Object.saveAll(rootObjects);
334427

335-
return measureOperation('Query with Include (2 levels)', async () => {
428+
const result = await measureOperation('Query with Include (2 levels)', async () => {
336429
const query = new Parse.Query('Root');
337430
query.include('level1.level2');
338431
await query.find();
339-
}, Math.floor(ITERATIONS / 10)); // Fewer iterations for complex queries
432+
});
433+
434+
return result;
340435
}
341436

342437
/**
@@ -349,6 +444,9 @@ async function runBenchmarks() {
349444
let server;
350445

351446
try {
447+
// Start MongoDB proxy
448+
await startProxy();
449+
352450
// Initialize Parse Server
353451
console.log('Initializing Parse Server...');
354452
server = await initializeParseServer();
@@ -358,38 +456,26 @@ async function runBenchmarks() {
358456

359457
const results = [];
360458

361-
// Run each benchmark with database cleanup
362-
console.log('Running Object Create benchmark...');
363-
await cleanupDatabase();
364-
results.push(await benchmarkObjectCreate());
365-
366-
console.log('Running Object Read benchmark...');
367-
await cleanupDatabase();
368-
results.push(await benchmarkObjectRead());
459+
// Define all benchmarks to run
460+
const benchmarks = [
461+
{ name: 'Object Create', fn: benchmarkObjectCreate },
462+
{ name: 'Object Read', fn: benchmarkObjectRead },
463+
{ name: 'Object Update', fn: benchmarkObjectUpdate },
464+
{ name: 'Simple Query', fn: benchmarkSimpleQuery },
465+
{ name: 'Batch Save', fn: benchmarkBatchSave },
466+
{ name: 'User Signup', fn: benchmarkUserSignup },
467+
{ name: 'User Login', fn: benchmarkUserLogin },
468+
{ name: 'Query with Include', fn: benchmarkQueryWithInclude },
469+
];
369470

370-
console.log('Running Object Update benchmark...');
371-
await cleanupDatabase();
372-
results.push(await benchmarkObjectUpdate());
373-
374-
console.log('Running Simple Query benchmark...');
375-
await cleanupDatabase();
376-
results.push(await benchmarkSimpleQuery());
377-
378-
console.log('Running Batch Save benchmark...');
379-
await cleanupDatabase();
380-
results.push(await benchmarkBatchSave());
381-
382-
console.log('Running User Signup benchmark...');
383-
await cleanupDatabase();
384-
results.push(await benchmarkUserSignup());
385-
386-
console.log('Running User Login benchmark...');
387-
await cleanupDatabase();
388-
results.push(await benchmarkUserLogin());
389-
390-
console.log('Running Query with Include benchmark...');
391-
await cleanupDatabase();
392-
results.push(await benchmarkQueryWithInclude());
471+
// Run each benchmark with database cleanup
472+
for (const benchmark of benchmarks) {
473+
console.log(`Running ${benchmark.name} benchmark...`);
474+
resetParseServer();
475+
await cleanupDatabase();
476+
results.push(await benchmark.fn());
477+
await cleanupProxyServer();
478+
}
393479

394480
// Output results in github-action-benchmark format (stdout)
395481
console.log(JSON.stringify(results, null, 2));
@@ -412,8 +498,9 @@ async function runBenchmarks() {
412498
if (server) {
413499
server.close();
414500
}
501+
await stopProxy();
415502
// Give some time for cleanup
416-
setTimeout(() => process.exit(0), 10000);
503+
setTimeout(() => process.exit(0), 1000);
417504
}
418505
}
419506

0 commit comments

Comments
 (0)