Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow pty.kill to be awaited #734

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

TheLazySquid
Copy link

Currently there isn't a good way to know when a pseudoterminal is fully killed, since there is some asynchronous logic on windows. This means that there isn't a good way to clean up any active pseudoterminals in electron before shutdown, as described in #733, because if the app is quit before the terminals are fully killed the process will hang. This PR allows pty.kill to be awaited, so the app can be shut down only after any pseudoterminals are fully killed, making a clean solution like this possible:

const { app } = require("electron");
const { spawn } = require("node-pty");

app.whenReady().then(async () => {
    let pty = spawn("cmd.exe");

    // process exits normally
    await pty.kill();
    app.quit();
});

@TheLazySquid
Copy link
Author

@microsoft-github-policy-service agree

Comment on lines 170 to 176
return new Promise((res) => {
this._deferNoArgs(() => {
if (signal) {
throw new Error('Signals not supported on windows.');
}
this._close();
this._agent.kill().then(res);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn’t the outer promise be rejected when the this._agent.kill() promise fails?

Suggested change
return new Promise((res) => {
this._deferNoArgs(() => {
if (signal) {
throw new Error('Signals not supported on windows.');
}
this._close();
this._agent.kill().then(res);
return new Promise((res, rej) => {
this._deferNoArgs(() => {
if (signal) {
throw new Error('Signals not supported on windows.');
}
this._close();
this._agent.kill().then(res, rej);

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may or may not be out of scope for this PR, but anyway.

As far as I can tell, the callbacks passed to this._deferNoArgs are called later, asynchronously. So it looks like the throw here cannot be caught. This is not a new issue in this PR. But with this PR, it’s less expected to throw errors since the function returns a Promise – I’d expect the promise to be rejected instead. We have the possibility to do that:

Suggested change
return new Promise((res) => {
this._deferNoArgs(() => {
if (signal) {
throw new Error('Signals not supported on windows.');
}
this._close();
this._agent.kill().then(res);
return new Promise((res, rej) => {
this._deferNoArgs(() => {
if (signal) {
rej(new Error('Signals not supported on windows.'));
} else {
this._close();
this._agent.kill().then(res, rej);
}

However, I don’t know if this is wanted or not by end consumers. They can always check caughtError.message === 'Signals not supported on windows.' but 🤷

If this change is made, this line needs to be updated in node-pty.d.ts:

@throws Will throw when signal is used on Windows.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it makes more sense to reject the promise if signal is used, especially if the thrown error would sometimes not be caught. I'm not entirely sure how promise rejections should be described in jsdoc, but changing it to @throws Will reject when signal is used on Windows. seems to be fine.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

Note that your commit (unlike my suggestion above) changes behavior: Previously, this._close() and this._agent.kill() were not run if signal is truthy. In your commit, the promise is rejected and then those two methods are run anyway.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops, should be fixed now.

Copy link
Member

@Tyriar Tyriar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great change 👏

@rzhao271 looks like the SDL job is failing with a permissions problem.

@Tyriar Tyriar added this to the 1.1.0 milestone Dec 2, 2024
@rzhao271
Copy link
Contributor

rzhao271 commented Dec 2, 2024

I wouldn't be surprised if CI is failing because it is trying to run on a fork. #727, which splits the current pipeline into two and makes the CI pipeline use the unofficial template might help.

@Tyriar
Copy link
Member

Tyriar commented Dec 3, 2024

@rzhao271 can we get it to run on a PR branch that gets merged into main with an approve and run button? Alternatively, we could just have SDL blocking the release step and only run on main after the PR is merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants