mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-03 23:06:49 +01:00
refactor: enhance process instance registration and termination logging (#245409)
This commit is contained in:
@@ -38,18 +38,28 @@ interface ICodeInstance {
|
||||
|
||||
const instances = new Set<ICodeInstance>();
|
||||
|
||||
function registerInstance(process: cp.ChildProcess, logger: Logger, type: string) {
|
||||
function registerInstance(process: cp.ChildProcess, logger: Logger, type: 'electron' | 'server'): { safeToKill: Promise<void> } {
|
||||
const instance = { kill: () => teardown(process, logger) };
|
||||
instances.add(instance);
|
||||
|
||||
process.stdout?.on('data', data => logger.log(`[${type}] stdout: ${data}`));
|
||||
process.stderr?.on('data', error => logger.log(`[${type}] stderr: ${error}`));
|
||||
const safeToKill = new Promise<void>(resolve => {
|
||||
process.stdout?.on('data', data => {
|
||||
const output = data.toString();
|
||||
if (output.indexOf('calling app.quit()') >= 0 && type === 'electron') {
|
||||
setTimeout(() => resolve(), 500 /* give Electron some time to actually terminate fully */);
|
||||
}
|
||||
logger.log(`[${type}] stdout: ${output}`);
|
||||
});
|
||||
process.stderr?.on('data', error => logger.log(`[${type}] stderr: ${error}`));
|
||||
});
|
||||
|
||||
process.once('exit', (code, signal) => {
|
||||
logger.log(`[${type}] Process terminated (pid: ${process.pid}, code: ${code}, signal: ${signal})`);
|
||||
|
||||
instances.delete(instance);
|
||||
});
|
||||
|
||||
return { safeToKill };
|
||||
}
|
||||
|
||||
async function teardownAll(signal?: number) {
|
||||
@@ -85,15 +95,7 @@ export async function launch(options: LaunchOptions): Promise<Code> {
|
||||
// Electron smoke tests (playwright)
|
||||
else {
|
||||
const { electronProcess, driver } = await measureAndLog(() => launchPlaywrightElectron(options), 'launch playwright (electron)', options.logger);
|
||||
registerInstance(electronProcess, options.logger, 'electron');
|
||||
|
||||
const safeToKill = new Promise<void>(resolve => {
|
||||
process.stdout?.on('data', data => {
|
||||
if (data.toString().includes('Lifecycle#app.on(will-quit) - calling app.quit()')) {
|
||||
setTimeout(() => resolve(), 500 /* give Electron some time to actually terminate fully */);
|
||||
}
|
||||
});
|
||||
});
|
||||
const { safeToKill } = registerInstance(electronProcess, options.logger, 'electron');
|
||||
|
||||
return new Code(driver, options.logger, electronProcess, safeToKill, options.quality);
|
||||
}
|
||||
@@ -155,7 +157,10 @@ export class Code {
|
||||
this.driver.close();
|
||||
|
||||
let safeToKill = false;
|
||||
this.safeToKill?.then(() => safeToKill = true);
|
||||
this.safeToKill?.then(() => {
|
||||
this.logger.log('Smoke test exit(): safeToKill() called');
|
||||
safeToKill = true;
|
||||
});
|
||||
|
||||
// Await the exit of the application
|
||||
(async () => {
|
||||
@@ -164,25 +169,26 @@ export class Code {
|
||||
retries++;
|
||||
|
||||
if (safeToKill) {
|
||||
this.logger.log('Smoke test exit() call did not terminate the process yet, but safeToKill is true, so we can kill it');
|
||||
process.kill(pid);
|
||||
this.logger.log('Smoke test exit(): call did not terminate the process yet, but safeToKill is true, so we can kill it');
|
||||
this.kill(pid);
|
||||
}
|
||||
|
||||
switch (retries) {
|
||||
|
||||
// after 10 seconds: forcefully kill
|
||||
case 20: {
|
||||
this.logger.log('Smoke test exit() call did not terminate process after 10s, forcefully exiting the application...');
|
||||
process.kill(pid);
|
||||
this.logger.log('Smoke test exit(): call did not terminate process after 10s, forcefully exiting the application...');
|
||||
this.kill(pid);
|
||||
break;
|
||||
}
|
||||
|
||||
// after 20 seconds: give up
|
||||
case 40: {
|
||||
this.logger.log('Smoke test exit() call did not terminate process after 20s, giving up');
|
||||
process.kill(pid);
|
||||
this.logger.log('Smoke test exit(): call did not terminate process after 20s, giving up');
|
||||
this.kill(pid);
|
||||
done = true;
|
||||
resolve();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,9 +196,9 @@ export class Code {
|
||||
process.kill(pid, 0); // throws an exception if the process doesn't exist anymore.
|
||||
await this.wait(500);
|
||||
} catch (error) {
|
||||
this.logger.log('Smoke test exit() call terminated process successfully');
|
||||
done = true;
|
||||
this.logger.log('Smoke test exit(): call terminated process successfully');
|
||||
|
||||
done = true;
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
@@ -200,6 +206,15 @@ export class Code {
|
||||
}), 'Code#exit()', this.logger);
|
||||
}
|
||||
|
||||
private kill(pid: number): void {
|
||||
try {
|
||||
this.logger.log(`Smoke test exit(): Trying to SIGTERM process: ${pid}`);
|
||||
process.kill(pid);
|
||||
} catch (e) {
|
||||
this.logger.log('Smoke test exit(): SIGTERM failed', e);
|
||||
}
|
||||
}
|
||||
|
||||
async getElement(selector: string): Promise<IElement | undefined> {
|
||||
return (await this.driver.getElements(selector))?.[0];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user