When a terminal application that spawns child processes doesn't exit cleanly after a Ctrl+C, the user is left with a corrupted terminal. Instead of a clean prompt, you get garbled output and a non-functional shell. This post covers how to solve these issues, with examples from the Moose CLI (for the PR that fixed many of these issues, see here). In this post, you’ll read learnings from solving these issues in the Moose CLI— terminal application that manages multiple child processes, including Docker containers, TypeScript compilers, and background workers. The Problems: Terminal Corruption and Hanging Processes Terminal corruption manifests in several ways: Terminal State Corruption: After Ctrl+C, the terminal cursor might be hidden, raw mode might still be enabled, or the alternate screen buffer might still be active Child Process Output Interference: Child processes continue writing to stdout/stderr, mixing with your shell prompt Hanging Background Processes: Child processes don't receive proper termination signals and continue running Race Conditions: Cleanup code races with child process output, leading to unpredictable terminal state How We Solved It 1. Process Output Proxying Child process output must be completely isolated from the terminal. Direct child process output to the terminal creates race conditions and corruption. Key principles: Pipe all child process stdio: Use Stdio::piped() for stdout/stderr and Stdio::null() for stdin. Stdio::piped() will create a new pipe that is going to be readable by the parent process but will only be written to the stdout of the parent if explicitly done. And Stdio::null() will enable to ignore the inputs. Proxy to logging system: Forward child process output to your logging system instead of directly to terminal Handle I/O errors gracefully: child process streams can fail; don't let that crash your proxy Wait for completion: Ensure all output is read before proceeding with cleanup 2. Terminal State Management Terminal ap...
First seen: 2025-07-30 23:56
Last seen: 2025-07-31 12:59