@@ -71,6 +71,7 @@ runInEachFileSystem(() => {
7171 }
7272 return lockFileContents ;
7373 } ) ;
74+ spyOn ( process , 'kill' ) . and . returnValue ( ) ;
7475
7576 const promise = locker . lock ( async ( ) => log . push ( 'fn()' ) ) ;
7677 // The lock is now waiting on the lock-file becoming free, so no `fn()` in the log.
@@ -80,6 +81,7 @@ runInEachFileSystem(() => {
8081 `(If you are sure no ngcc process is running then you should delete the lock-file at ${
8182 lockFile . path } .)`
8283 ] ] ) ;
84+ expect ( process . kill ) . toHaveBeenCalledWith ( 188 , 0 ) ;
8385
8486 lockFileContents = null ;
8587 // The lock-file has been removed, so we can create our own lock-file, call `fn()` and then
@@ -88,6 +90,47 @@ runInEachFileSystem(() => {
8890 expect ( log ) . toEqual ( [ 'write()' , 'read() => 188' , 'write()' , 'fn()' , 'remove()' ] ) ;
8991 } ) ;
9092
93+ it ( 'should fail fast when waiting on a dead process' , async ( ) => {
94+ const fs = getFileSystem ( ) ;
95+ const log : string [ ] = [ ] ;
96+ const lockFile = new MockLockFile ( fs , log ) ;
97+ const logger = new MockLogger ( ) ;
98+ const locker = new AsyncLocker ( lockFile , logger , 100 , 10 ) ;
99+
100+ let lockFileContents : string | null = '188' ;
101+ spyOn ( lockFile , 'write' ) . and . callFake ( ( ) => {
102+ log . push ( 'write()' ) ;
103+ if ( lockFileContents ) {
104+ throw { code : 'EEXIST' } ;
105+ }
106+ } ) ;
107+ spyOn ( lockFile , 'read' ) . and . callFake ( ( ) => {
108+ log . push ( 'read() => ' + lockFileContents ) ;
109+ if ( lockFileContents === null ) {
110+ throw { code : 'ENOENT' } ;
111+ }
112+ return lockFileContents ;
113+ } ) ;
114+ spyOn ( process , 'kill' ) . and . callFake ( ( ) => {
115+ throw { code : 'ESRCH' } ;
116+ } ) ;
117+
118+ const promise = locker . lock ( async ( ) => log . push ( 'fn()' ) ) ;
119+ // The lock has already failed so no `fn()` in the log.
120+ expect ( log ) . toEqual ( [ 'write()' , 'read() => 188' , 'write()' , 'read() => 188' ] ) ;
121+ expect ( logger . logs . info ) . toEqual ( [ ] ) ;
122+ expect ( process . kill ) . toHaveBeenCalledWith ( 188 , 0 ) ;
123+ // Check that a missing process errors out.
124+ let error : Error ;
125+ await promise . catch ( e => error = e ) ;
126+ expect ( log ) . toEqual ( [ 'write()' , 'read() => 188' , 'write()' , 'read() => 188' ] ) ;
127+ expect ( error ! . message )
128+ . toEqual (
129+ `Lock found, but no process with PID 188 seems to be running.\n` +
130+ `(If you are sure no ngcc process is running then you should delete the lock-file at ${
131+ lockFile . path } .)`) ;
132+ } ) ;
133+
91134 it ( 'should extend the retry timeout if the other process locking the file changes' , async ( ) => {
92135 const fs = getFileSystem ( ) ;
93136 const log : string [ ] = [ ] ;
@@ -109,6 +152,7 @@ runInEachFileSystem(() => {
109152 }
110153 return lockFileContents ;
111154 } ) ;
155+ spyOn ( process , 'kill' ) . and . returnValue ( ) ;
112156
113157 const promise = locker . lock ( async ( ) => log . push ( 'fn()' ) ) ;
114158 // The lock is now waiting on the lock-file becoming free, so no `fn()` in the log.
@@ -118,6 +162,7 @@ runInEachFileSystem(() => {
118162 `(If you are sure no ngcc process is running then you should delete the lock-file at ${
119163 lockFile . path } .)`
120164 ] ] ) ;
165+ expect ( process . kill ) . toHaveBeenCalledWith ( 188 , 0 ) ;
121166
122167 lockFileContents = '444' ;
123168 // The lock-file has been taken over by another process - wait for the next attempt
@@ -131,6 +176,7 @@ runInEachFileSystem(() => {
131176 `(If you are sure no ngcc process is running then you should delete the lock-file at ${
132177 lockFile . path } .)`]
133178 ] ) ;
179+ expect ( process . kill ) . toHaveBeenCalledWith ( 444 , 0 ) ;
134180
135181 lockFileContents = null ;
136182 // The lock-file has been removed, so we can create our own lock-file, call `fn()` and
@@ -163,11 +209,13 @@ runInEachFileSystem(() => {
163209 }
164210 return lockFileContents ;
165211 } ) ;
212+ spyOn ( process , 'kill' ) . and . returnValue ( ) ;
166213
167214 const promise = locker . lock ( async ( ) => log . push ( 'fn()' ) ) ;
168215
169216 // The lock is now waiting on the lock-file becoming free, so no `fn()` in the log.
170217 expect ( log ) . toEqual ( [ 'write()' , 'read() => 188' ] ) ;
218+ expect ( process . kill ) . toHaveBeenCalledWith ( 188 , 0 ) ;
171219 // Do not remove the lock-file and let the call to `lock()` timeout.
172220 let error : Error ;
173221 await promise . catch ( e => error = e ) ;
0 commit comments