@@ -13,7 +13,7 @@ const key = 'pid';
1313const millis = 10000 ;
1414const none = - 1 ;
1515const prefix = 'Trace Server' ;
16- const suffix = ' failure or so .' ;
16+ const suffix = ' failure.' ;
1717const SHUTDOWN_DELAY = 2000 ;
1818
1919export class TraceServer {
@@ -24,15 +24,21 @@ export class TraceServer {
2424 const server = spawn ( this . getPath ( from ) , this . getArgs ( from ) ) ;
2525
2626 if ( ! server . pid ) {
27- this . showError ( prefix + ' startup' + suffix ) ;
27+ // Failed to spawn the child process due to errors, PID is undefined and an error is emitted.
28+ await new Promise < void > ( resolve => {
29+ server . once ( 'error' , error => {
30+ this . showError ( prefix + ' startup' + suffix + ': ' + error ) ;
31+ } ) ;
32+ resolve ( ) ;
33+ } ) ;
2834 return ;
2935 }
3036 this . server = server ;
3137 await context ?. workspaceState . update ( key , this . server . pid ) ;
3238 await this . waitFor ( context ) ;
3339 }
3440
35- async stopOrReset ( context : vscode . ExtensionContext | undefined ) {
41+ async stopOrReset ( context : vscode . ExtensionContext | undefined , reportNotStopped : boolean = true ) {
3642 const pid : number | undefined = context ?. workspaceState . get ( key ) ;
3743 const not = prefix + ' not stopped as none running or owned by us.' ;
3844 if ( pid === none ) {
@@ -43,6 +49,7 @@ export class TraceServer {
4349 let id : NodeJS . Timeout ;
4450 // recovering from workspaceState => no this.server set
4551 if ( this . server ) {
52+ this . server . removeAllListeners ( ) ;
4653 this . server . once ( 'exit' , ( ) => {
4754 this . showStatus ( false ) ;
4855 clearTimeout ( id ) ;
@@ -56,6 +63,7 @@ export class TraceServer {
5663 } ,
5764 async progress => {
5865 progress . report ( { message : 'stopping...' } ) ;
66+ // Remove all existing listeners to avoid unnecessary pop-ups
5967 const message = prefix + ' stopping' + suffix + ' Resetting.' ;
6068 treeKill ( pid , error => {
6169 if ( error ) {
@@ -66,7 +74,7 @@ export class TraceServer {
6674 } ) ;
6775 }
6876 ) ;
69- } else {
77+ } else if ( reportNotStopped ) {
7078 vscode . window . showWarningMessage ( not ) ;
7179 }
7280 await context ?. workspaceState . update ( key , none ) ;
@@ -81,6 +89,9 @@ export class TraceServer {
8189 return ;
8290 }
8391 if ( pid ) {
92+ // Remove all existing listeners to avoid unnecessary pop-ups
93+ this . server ?. removeAllListeners ( ) ;
94+
8495 treeKill ( pid ) ;
8596 // Allow the treeKill to finish collecting and killing all
8697 // spawned processes.
@@ -160,6 +171,10 @@ export class TraceServer {
160171 }
161172
162173 private async waitFor ( context : vscode . ExtensionContext | undefined ) {
174+ if ( this . server === undefined ) {
175+ return ;
176+ }
177+ const server = this . server ;
163178 await vscode . window . withProgress (
164179 {
165180 location : vscode . ProgressLocation . Notification ,
@@ -168,27 +183,63 @@ export class TraceServer {
168183 } ,
169184 async progress => {
170185 progress . report ( { message : 'starting up...' } ) ;
171- let timeout = false ;
172- const timeoutId = setTimeout ( ( ) => ( timeout = true ) , millis ) ;
173-
174- // eslint-disable-next-line no-constant-condition
175- while ( true ) {
176- if ( await this . isUp ( ) ) {
177- this . showStatus ( true ) ;
178- clearTimeout ( timeoutId ) ;
179- break ;
180- }
181- if ( timeout ) {
182- this . showError ( prefix + ' startup timed-out after ' + millis + 'ms.' ) ;
183- await this . stopOrReset ( context ) ;
184- break ;
186+ try {
187+ let timeout = false ;
188+ const timeoutId = setTimeout ( ( ) => ( timeout = true ) , millis ) ;
189+
190+ let stderr = '' ;
191+ server . stderr ?. once ( 'data' , data => {
192+ stderr = data ;
193+ } ) ;
194+
195+ let errorString : string | undefined ;
196+ server . once ( 'exit' , code => {
197+ errorString = 'Code: ' + code + ( stderr !== '.' ? '. Error message: ' + stderr : '' ) ;
198+ } ) ;
199+
200+ // eslint-disable-next-line no-constant-condition
201+ while ( true ) {
202+ if ( await this . isUp ( ) ) {
203+ clearTimeout ( timeoutId ) ;
204+ this . showStatus ( true ) ;
205+ break ;
206+ }
207+
208+ // Check if trace server exited with error
209+ if ( errorString !== undefined ) {
210+ throw new Error ( errorString ) ;
211+ }
212+
213+ // Check for overall timeout
214+ if ( timeout ) {
215+ await this . stopOrReset ( context , false ) ;
216+ throw new Error ( prefix + ' startup timed-out after ' + millis + 'ms.' ) ;
217+ }
218+
219+ // Wait before trying again
220+ await new Promise < void > ( resolve => setTimeout ( ( ) => resolve ( ) , 1000 ) ) ;
185221 }
222+ } catch ( error ) {
223+ this . showErrorDetailed ( prefix + ' starting up' + suffix , error as Error ) ;
224+ return ;
225+ } finally {
226+ // Remove all listener needed during startup
227+ server . removeAllListeners ( ) ;
228+ // Add listener to catch when server exits unexpectedly
229+ server . once ( 'exit' , code => {
230+ context ?. workspaceState . update ( key , none ) ;
231+ this . server = undefined ;
232+ this . setStatusIfAvailable ( false ) ;
233+ vscode . window . showErrorMessage (
234+ prefix + ' exited unexpectedly' + ( code !== null ? ' with code ' + code : '' ) + '!'
235+ ) ;
236+ } ) ;
186237 }
187238 }
188239 ) ;
189240 }
190241
191- private async isUp ( ) {
242+ private async isUp ( ) : Promise < boolean > {
192243 const client = new TspClient ( this . getServerUrl ( ) ) ;
193244 const health = await client . checkHealth ( ) ;
194245 const status = health . getModel ( ) ?. status ;
@@ -198,18 +249,15 @@ export class TraceServer {
198249 private async showError ( message : string ) {
199250 console . error ( message ) ;
200251 vscode . window . showErrorMessage ( message ) ;
201- const disclaimer = ' running, despite this error.' ;
202252 const up = await this . isUp ( ) ;
203253 if ( up ) {
204- vscode . window . showWarningMessage ( prefix + ' is still' + disclaimer ) ;
205- } else {
206- vscode . window . showWarningMessage ( prefix + ' is not' + disclaimer ) ;
254+ vscode . window . showWarningMessage ( prefix + ' is still running, despite this error.' ) ;
207255 }
208256 this . setStatusIfAvailable ( up ) ;
209257 }
210258
211259 private showErrorDetailed ( message : string , error : Error ) {
212- const details = error . name + ' - ' + error . message ;
260+ const details = error . name + ' - ' + error ? .message ;
213261 vscode . window . showErrorMessage ( details ) ;
214262 console . error ( details ) ;
215263 this . showError ( message ) ;
0 commit comments