// Stop only ChildProcess objects created by this runner. Preserve downstream
// availability: checkout drains first, then pricing. A failed stop never skips
// the remaining children; all outcomes are observed before returning.
export async function stopChildren(children,{graceMs=10000,killWaitMs=1000}={}){
 function stopOne(child){
  if(child.exitCode!==null||child.signalCode!==null)return Promise.resolve();
  return new Promise((resolve,reject)=>{
   let forced=false,finished=false,forceTimer;
   const done=error=>{if(finished)return;finished=true;clearTimeout(graceTimer);clearTimeout(forceTimer);child.off('exit',onExit);child.off('error',onError);error?reject(error):resolve();};
   const onExit=(code,signal)=>done(forced?Error(`Own child ${child.pid} exceeded shutdown deadline and was force-killed`):code===0?null:Error(`Own child ${child.pid} exited with ${code??signal}`));
   const onError=error=>done(error);
   const graceTimer=setTimeout(()=>{forced=true;child.kill('SIGKILL');forceTimer=setTimeout(()=>done(Error(`Own child ${child.pid} did not confirm exit after force-kill`)),killWaitMs);},graceMs);
   child.once('exit',onExit);child.once('error',onError);
   if(child.connected){child.send({type:'shutdown'},error=>{if(error&&child.exitCode!==null)done(error);});}
   else child.kill('SIGTERM');
  });
 }
 let previous=Promise.resolve();
 const pending=[...children].reverse().map(child=>{const next=previous.catch(()=>{}).then(()=>stopOne(child));previous=next;return next;});
 const outcomes=await Promise.allSettled(pending),errors=outcomes.filter(x=>x.status==='rejected').map(x=>x.reason);
 if(errors.length)throw new AggregateError(errors,'One or more own services failed to stop cleanly: '+errors.map(e=>e.message).join('; '));
}
