@@ -17,25 +17,60 @@ test(
1717 const child = spawn (
1818 process . execPath ,
1919 [
20+ '--expose-gc' ,
2021 '--input-type=module' ,
2122 '-e' ,
2223 `
24+ import { setTimeout as delay } from 'node:timers/promises';
2325 import { withProcessLock } from ${ JSON . stringify ( moduleUrl ) } ;
2426 await withProcessLock(${ JSON . stringify ( path ) } , async () => {
25- process.stdout.write('locked');
26- await new Promise(() => { setInterval(() => {}, 1000); });
27+ setImmediate(() => {
28+ global.gc();
29+ setImmediate(() => process.send('locked'));
30+ });
31+ // The timer retains its resolver and the lock-owning async frame.
32+ await delay(60_000);
2733 });
2834 ` ,
2935 ] ,
30- { stdio : [ 'ignore' , 'pipe' , 'pipe' ] }
36+ { stdio : [ 'ignore' , 'pipe' , 'pipe' , 'ipc' ] }
3137 ) ;
38+ let stdout = '' ;
39+ let stderr = '' ;
40+ child . stdout ! . setEncoding ( 'utf8' ) . on ( 'data' , ( chunk : string ) => {
41+ stdout = ( stdout + chunk ) . slice ( - 4096 ) ;
42+ } ) ;
43+ child . stderr ! . setEncoding ( 'utf8' ) . on ( 'data' , ( chunk : string ) => {
44+ stderr = ( stderr + chunk ) . slice ( - 4096 ) ;
45+ } ) ;
3246 const closed = once ( child , 'close' ) ;
3347 t . after ( async ( ) => {
3448 child . kill ( 'SIGKILL' ) ;
35- await closed ;
36- await rm ( directory , { recursive : true , force : true } ) ;
49+ try {
50+ await closed ;
51+ } finally {
52+ t . diagnostic (
53+ JSON . stringify ( {
54+ stdout,
55+ stderr,
56+ exitCode : child . exitCode ,
57+ signal : child . signalCode ,
58+ } )
59+ ) ;
60+ await rm ( directory , { recursive : true , force : true } ) ;
61+ }
3762 } ) ;
38- await once ( child . stdout ! , 'data' ) ;
63+ await Promise . race ( [
64+ once ( child , 'message' , { signal : t . signal } ) . then ( ( [ marker ] ) => {
65+ assert . equal ( marker , 'locked' ) ;
66+ t . diagnostic ( 'Lock owner ready: locked (after GC)' ) ;
67+ } ) ,
68+ closed . then ( ( [ code , signal ] ) => {
69+ throw new Error (
70+ `Lock owner exited before readiness: ${ code } /${ signal } `
71+ ) ;
72+ } ) ,
73+ ] ) ;
3974 let entered = false ;
4075 await assert . rejects (
4176 withProcessLock (
4782 )
4883 ) ;
4984 assert . equal ( entered , false ) ;
85+ assert . equal ( child . exitCode , null ) ;
86+ assert . equal ( child . signalCode , null ) ;
5087 child . kill ( 'SIGKILL' ) ;
51- await closed ;
88+ assert . deepEqual ( await closed , [ null , 'SIGKILL' ] ) ;
5289 await withProcessLock (
5390 path ,
5491 async ( ) => {
0 commit comments