-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
Enable ConPTY by default in terminals on Windows #44468
Conversation
🤖 Vercel preview here: https://docs-8s5hko9h5-goteleport.vercel.app/docs/ver/preview |
…ass boolean all the way through
🤖 Vercel preview here: https://docs-flcylr3w1-goteleport.vercel.app/docs/ver/preview |
@@ -76,8 +82,7 @@ export class PtyProcess extends EventEmitter implements IPtyProcess { | |||
// https://unix.stackexchange.com/questions/123858 | |||
cwd: this.options.cwd || getDefaultCwd(this.options.env), | |||
env: this.options.env, | |||
// Turn off ConPTY due to an uncaught exception being thrown when a PTY is closed. | |||
useConpty: false, | |||
useConpty: this.options.useConpty, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That isn't the case with winpty, where a new conhost.exe is created, but it goes away when closing Connect. conhost.exe spawned by winpty doesn't have those extra arguments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm trying to reproduce it, but with no luck.
In the recording below, conhost.exe
processes are killed both when closing tabs one by one and when closing the entire app:
conhostmov.mov
I also don't see these extra arguments.
EDIT: I had that column disabled in the task manager, nvm.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've just tried your build. conhost.exe goes away when starting a local terminal. But when connecting through SSH to a node, it stays open after closing Connect.
I've tested this only with SSH nodes. Because of the bug with the css
prop, I cannot access additional action menu and because the shortcut to open a new terminal tab doesn't work inside the VM, I couldn't open a local terminal. ;f
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can confirm, it happens for SSH connections.
I'm trying to to dispose the pty processes when the shared process exits, but it's quite hard to debug since I can't get any logs from there when the main process kills it :(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd look if there are any extra node-pty options there to take care of the issue or if someone else had the same problem. It's interesting that this happens with ConPTY but not winpty.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't find any node-pty
options that would take care of that. When it comes to similar issues, I found some (microsoft/node-pty#333, Eugeny/tabby#6318).
The most useful seems this PR from vscode microsoft/vscode#118437.
However, it seems to me that simply killing all pty process on exit would work. I tested this by setting a 30 seconds timeout after the shared process launched; after that, I didn't see any remaining conhost.exe
processes.
The problem is that process.on('exit')
doesn't seem to work on Windows and our cleanup code is not invoked at all :/ I think we need to send a graceful kill message to the shared process in a different way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I'm making progress:
- To gracefully kill the shared process we can send a message through the Node.js IPC:
terminateWithTimeout(this.sharedProcess, 5_000, process =>
process.send('gracefullyKill')
)
and then listen for it on the Node.js side:
process.on('message', message => {
if (message === 'gracefullyKill') {
server.forceShutdown();
ptyHostService.dispose();
process.exit(0);
}
});
This works fine.
2. It turned out that simply killing all processes and then exiting doesn't work (as I said before). Adding a timeout before process.exit(0)
helps, I'm looking now what timeouts vscode uses.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have it 🥵
To make it work I needed two things:
- Gracefully killing the shared process on Windows (done with
process.send
). - Waiting for the pty processes to exit before closing the app. Killing the pty process takes some time (from my testing, the time between calling
ptyProcess.kill
andptyProcess.onExit
was around 400 ms). If I'm correct, in vsocde they set timeouts to achieve waiting for processes to exit, but I thought that the better option is to simply wait foronExit
to be called (I took an inspiration fromterminateWithTimeout
).
Tested on Windows with ConPTY enabled/disabled and on macOS. I didn't see any unterminated processes.
Screen.Recording.2024-07-25.at.17.03.15.mov
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Requesting changes because of the processes left over.
🤖 Vercel preview here: https://docs-ebg5kb4jz-goteleport.vercel.app/docs/ver/preview |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good. 👍
I'm not sure how I feel about the graceful kill message through IPC, especially since we already have "infrastructure" in place to gracefully terminate tsh on Windows. OTOH, the way we kill tsh on Windows is a huge workaround, so perhaps it's best to stick to IPC which is guaranteed to work.
web/packages/teleterm/src/sharedProcess/ptyHost/ptyHostService.ts
Outdated
Show resolved
Hide resolved
@@ -276,3 +276,5 @@ export enum MainProcessIpc { | |||
export enum WindowsManagerIpc { | |||
SignalUserInterfaceReadiness = 'windows-manager-signal-user-interface-readiness', | |||
} | |||
|
|||
export const GRACEFUL_KILL_MESSAGE = 'GRACEFUL_KILL'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about TERMINATE_MESSAGE
instead? SIGKILL just ends a process with no hesitation, the graceful version of it has a name and it's SIGTERM. ;)
Also, please add a JSDoc explaining what the message signals.
Yeah, I thought about it, but simplicity of |
🤖 Vercel preview here: https://docs-7kiakc9sx-goteleport.vercel.app/docs/ver/preview |
🤖 Vercel preview here: https://docs-lf1zcxzj1-goteleport.vercel.app/docs/ver/preview |
* Add `terminal.windowsUseConpty` config option * Calculate `windowsPty` options * Pass `useConpty` to node-pty * Pass `windowsPty` to xterm * Fix test * Replace `terminal.windowsUseConpty` with `terminal.windowsBackend`, pass boolean all the way through * Wait for pty processes to exit before closing the app * Simplify `Array.from` * `GRACEFUL_KILL_MESSAGE` -> `TERMINATE_MESSAGE` * Adjust callsites to async `dispose` * Add `winpty` to ignored words in `cspell.json` (cherry picked from commit 981aed6)
I wanted to do a backport to v14, but there were too many conflicts. |
* Add `terminal.windowsUseConpty` config option * Calculate `windowsPty` options * Pass `useConpty` to node-pty * Pass `windowsPty` to xterm * Fix test * Replace `terminal.windowsUseConpty` with `terminal.windowsBackend`, pass boolean all the way through * Wait for pty processes to exit before closing the app * Simplify `Array.from` * `GRACEFUL_KILL_MESSAGE` -> `TERMINATE_MESSAGE` * Adjust callsites to async `dispose` * Add `winpty` to ignored words in `cspell.json` (cherry picked from commit 981aed6)
Closes #38087
ConPTY is an official Windows API for bridging discrepancies between Unix-style terminals and Windows consoles.
It's better at rendering colors and handling resizing (although this one is still not ideal) than winpty.
Implementation
We detect Windows version in
ptyService.ts
and based on that decide if ConPTY should be enabled or not. Then we pass that information to two places:node-pty
andxterm.js
.There is a chance that ConPTY may not work well in some setups. Because of that it can be disabled using
terminal.windowsBackend
in the app config.Changelog: Teleport Connect now uses ConPTY for better terminal resizing and accurate color rendering on Windows, with an option to disable it in the app config