@@ -153,6 +153,27 @@ const _tree = ({ cb = noop, opts, sync = false }: {
153153 }
154154}
155155
156+ /**
157+ * Returns a `lookup()` snapshot started at or after `since`, dedupes concurrent callers.
158+ * Lets parallel `kill()` polls share a single `ps` invocation: join the in-flight one
159+ * if it's fresh enough, otherwise wait for the next queued one.
160+ */
161+ type TSnapshot = { startedAt : number , list : TPsLookupEntry [ ] }
162+ let inflight : { startedAt : number , promise : Promise < TSnapshot > } | null = null
163+ let queued : Promise < TSnapshot > | null = null
164+ const sharedSnapshot = ( since : number ) : Promise < TSnapshot > => {
165+ if ( inflight && inflight . startedAt >= since ) return inflight . promise
166+ if ( queued ) return queued
167+ const after = inflight ?. promise . catch ( noop ) ?? Promise . resolve ( )
168+ return queued = after . then ( ( ) => {
169+ queued = null
170+ const startedAt = Date . now ( )
171+ const promise = lookup ( ) . then ( list => ( { startedAt, list } ) )
172+ inflight = { startedAt, promise }
173+ return promise . finally ( ( ) => { inflight = inflight ?. promise === promise ? null : inflight } )
174+ } )
175+ }
176+
156177export const pickTree = ( list : TPsLookupEntry [ ] , pid : string | number , recursive = false ) : TPsLookupEntry [ ] => {
157178 const children = list . filter ( p => p . ppid === String ( pid ) )
158179 return [
@@ -173,48 +194,37 @@ export const kill = (pid: string | number, opts?: TPsNext | TPsKillOptions | TPs
173194
174195 const { promise, resolve, reject } = makeDeferred ( )
175196 const { timeout = 30 , signal = 'SIGTERM' , interval = 200 } = opts || { }
197+ const sPid = String ( pid )
198+ let done = false
199+ const settle = ( err ?: unknown ) => {
200+ if ( done ) return
201+ done = true
202+ clearTimeout ( timer )
203+ err ? reject ( err ) : resolve ( pid )
204+ next ?.( err ?? null , pid )
205+ }
176206
207+ let timer : NodeJS . Timeout
177208 try {
178209 process . kill ( + pid , signal )
179210 } catch ( e ) {
180- reject ( e )
181- next ?.( e )
211+ settle ( e )
182212 return promise
183213 }
184214
185- let confirmCount = 0
186- let timedOut = false
187-
188- const timer = setTimeout ( ( ) => {
189- timedOut = true
190- const err = new Error ( 'Kill process timeout' )
191- reject ( err )
192- next ?.( err )
193- } , timeout * 1000 )
194-
195- const poll = ( ) =>
196- lookup ( { pid } , ( err , list = [ ] ) => {
197- if ( timedOut ) return
198- if ( err ) {
199- clearTimeout ( timer )
200- reject ( err )
201- next ?.( err , pid )
202- return
203- }
204- if ( list . length > 0 ) {
205- confirmCount = Math . max ( confirmCount - 1 , 0 )
206- setTimeout ( poll , interval )
207- return
208- }
209- confirmCount ++
210- if ( confirmCount >= 5 ) {
211- clearTimeout ( timer )
212- resolve ( pid )
213- next ?.( null , pid )
215+ let since = Date . now ( )
216+ timer = setTimeout ( ( ) => settle ( new Error ( 'Kill process timeout' ) ) , timeout * 1000 )
217+
218+ const poll = ( ) : unknown =>
219+ sharedSnapshot ( since ) . then ( ( { startedAt, list } ) => {
220+ if ( done ) return
221+ since = startedAt + 1
222+ if ( list . some ( p => p . pid === sPid ) ) {
223+ setTimeout ( poll , Math . max ( 0 , startedAt + interval - Date . now ( ) ) )
214224 } else {
215- setTimeout ( poll , interval )
225+ settle ( )
216226 }
217- } )
227+ } , settle )
218228
219229 poll ( )
220230 return promise
0 commit comments