Improvements
This commit is contained in:
Executable
+30
@@ -0,0 +1,30 @@
|
||||
// Opt-in loopback-only, read-only smoke load. Not a production capacity certification.
|
||||
const args=process.argv.slice(2);
|
||||
const argument=(key:string,fallback:string)=>{const i=args.indexOf(key);return i<0?fallback:args[i+1];};
|
||||
if(!args.includes('--consent'))throw new Error('Explicit --consent required; use only an isolated disposable local node.');
|
||||
const endpoint=new URL(argument('--node','http://127.0.0.1:3001'));
|
||||
if(!['127.0.0.1','[::1]'].includes(endpoint.hostname)||!['http:','https:'].includes(endpoint.protocol)||
|
||||
endpoint.username||endpoint.password||endpoint.pathname!=='/'||endpoint.search||endpoint.hash)throw new Error('Only literal loopback HTTP(S) origins are allowed. No remote load targets.');
|
||||
const concurrency=Number(argument('--concurrency','8')),count=Number(argument('--requests','100'));
|
||||
if(!Number.isInteger(concurrency)||concurrency<1||concurrency>32||!Number.isInteger(count)||count<1||count>1000)throw new Error('Concurrency 1–32; requests 1–1000.');
|
||||
let next=0,totalBytes=0;const statuses:Record<string,number>={};const latencies:number[]=[];
|
||||
const started=performance.now();
|
||||
await Promise.all(Array.from({length:concurrency},async()=>{
|
||||
while(next<count){const i=next++,start=performance.now();
|
||||
try{
|
||||
const response=await fetch(new URL(i%3===0?'/api/market':'/api/summary',endpoint),{redirect:'error',signal:AbortSignal.timeout(5000)});
|
||||
const reader=response.body?.getReader();let bytes=0;
|
||||
if(reader)try{for(;;){const part=await reader.read();if(part.done)break;bytes+=part.value.byteLength;if(bytes>2*1024*1024)throw new Error('Response too large');}}finally{await reader.cancel();reader.releaseLock();}
|
||||
totalBytes+=bytes;statuses[response.status]=(statuses[response.status]??0)+1;
|
||||
}catch{statuses.error=(statuses.error??0)+1;}
|
||||
latencies.push(performance.now()-start);
|
||||
}
|
||||
}));
|
||||
latencies.sort((a,b)=>a-b);
|
||||
const health=await fetch(new URL('/healthz',endpoint),{redirect:'error',signal:AbortSignal.timeout(5000)});
|
||||
console.log(JSON.stringify({scope:'loopback read-only smoke, not production benchmark',requests:count,concurrency,
|
||||
elapsedMs:Math.round(performance.now()-started),statuses,totalBytes,
|
||||
p50Ms:Math.round(latencies[Math.floor(latencies.length*.5)]??0),p95Ms:Math.round(latencies[Math.min(latencies.length-1,Math.floor(latencies.length*.95))]??0),
|
||||
healthStatus:health.status},null,2));
|
||||
await health.body?.cancel();
|
||||
if(statuses.error||health.status!==200)process.exitCode=1;
|
||||
Reference in New Issue
Block a user