forked from wangziqi/gongxue-base
feat: add docker capacity benchmark mode
This commit is contained in:
95
scripts/run-docker-4c16g-benchmark.js
Normal file
95
scripts/run-docker-4c16g-benchmark.js
Normal file
@@ -0,0 +1,95 @@
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
const repoRoot = process.cwd();
|
||||
const databaseUrl = process.env.DATABASE_URL || 'postgresql://postgres:postgres@127.0.0.1:54322/postgres';
|
||||
const apiBase = process.env.PERF_API_BASE || 'http://127.0.0.1:8787';
|
||||
const matrix = [
|
||||
{ name: 'read-30', duration: 120, concurrency: 30, ramp: 15, writes: false, ratio: 0 },
|
||||
{ name: 'mixed-50', duration: 60, concurrency: 50, ramp: 10, writes: true, ratio: 0.1 },
|
||||
{ name: 'mixed-100', duration: 60, concurrency: 100, ramp: 15, writes: true, ratio: 0.08 },
|
||||
];
|
||||
|
||||
function run(command, args, options = {}) {
|
||||
const result = spawnSync(command, args, {
|
||||
cwd: repoRoot,
|
||||
stdio: 'inherit',
|
||||
shell: process.platform === 'win32',
|
||||
env: {
|
||||
...process.env,
|
||||
DATABASE_URL: databaseUrl,
|
||||
AUTH_SESSION_SECRET: process.env.AUTH_SESSION_SECRET || 'development-session-secret-change-me',
|
||||
DB_POOL_MAX: process.env.DB_POOL_MAX || '10',
|
||||
BENCHMARK_API_CPUS: process.env.BENCHMARK_API_CPUS || '2.0',
|
||||
BENCHMARK_API_MEMORY: process.env.BENCHMARK_API_MEMORY || '4g',
|
||||
...options.env,
|
||||
},
|
||||
});
|
||||
if (result.status !== 0) {
|
||||
throw new Error(`${command} ${args.join(' ')} failed with exit code ${result.status}`);
|
||||
}
|
||||
}
|
||||
|
||||
function latestBenchmarkJson(before) {
|
||||
const dir = path.join(repoRoot, 'docs', 'refactor', 'performance-reports');
|
||||
const files = fs.existsSync(dir)
|
||||
? fs.readdirSync(dir)
|
||||
.filter(name => /^api-benchmark-\d{8}-\d{6}\.json$/.test(name))
|
||||
.map(name => path.join(dir, name))
|
||||
.filter(file => fs.statSync(file).mtimeMs >= before)
|
||||
.sort((a, b) => fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs)
|
||||
: [];
|
||||
if (!files[0]) throw new Error('Benchmark report JSON was not generated.');
|
||||
return path.relative(repoRoot, files[0]).replaceAll('\\', '/');
|
||||
}
|
||||
|
||||
function waitForHealth(timeoutMs = 60_000) {
|
||||
const started = Date.now();
|
||||
while (Date.now() - started < timeoutMs) {
|
||||
const result = spawnSync(process.execPath, ['-e', `fetch('${apiBase}/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))`], {
|
||||
cwd: repoRoot,
|
||||
stdio: 'ignore',
|
||||
shell: process.platform === 'win32',
|
||||
});
|
||||
if (result.status === 0) return;
|
||||
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 1000);
|
||||
}
|
||||
throw new Error(`API did not become healthy at ${apiBase}`);
|
||||
}
|
||||
|
||||
function main() {
|
||||
const generated = [];
|
||||
try {
|
||||
run('docker', ['compose', '-f', 'docker-compose.api.yml', '-f', 'docker-compose.api.benchmark.yml', 'up', '-d', '--build', 'api']);
|
||||
waitForHealth();
|
||||
for (const item of matrix) {
|
||||
const before = Date.now();
|
||||
run('node', ['scripts/api-performance-benchmark.js'], {
|
||||
env: {
|
||||
PERF_START_SERVER: 'false',
|
||||
PERF_API_BASE: apiBase,
|
||||
PERF_AUTH_MODE: 'app_session',
|
||||
PERF_DURATION_SECONDS: String(item.duration),
|
||||
PERF_CONCURRENCY: String(item.concurrency),
|
||||
PERF_RAMP_SECONDS: String(item.ramp),
|
||||
PERF_INCLUDE_WRITES: item.writes ? 'true' : 'false',
|
||||
PERF_PRACTICE_FLOW_RATIO: String(item.ratio),
|
||||
PERF_PRACTICE_FLOW_ANSWERS: '3',
|
||||
},
|
||||
});
|
||||
generated.push({ scenario: item.name, report: latestBenchmarkJson(before) });
|
||||
}
|
||||
console.log(JSON.stringify({ status: 'pass', apiBase, reports: generated }, null, 2));
|
||||
} finally {
|
||||
if (process.env.PERF_KEEP_DOCKER_API !== 'true') {
|
||||
spawnSync('docker', ['compose', '-f', 'docker-compose.api.yml', '-f', 'docker-compose.api.benchmark.yml', 'down'], {
|
||||
cwd: repoRoot,
|
||||
stdio: 'inherit',
|
||||
shell: process.platform === 'win32',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
Reference in New Issue
Block a user