From c3b7be9d2b13324d76749e4bc684da7f649a3c2e Mon Sep 17 00:00:00 2001 From: Chris Olszewski Date: Mon, 16 Sep 2024 14:20:13 -0400 Subject: [PATCH] fix(watch): await persistent run task instead of abort (#9152) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Description This PR fixes an issue where the TUI was getting events from a previous run after an `update_tasks` call causing it to exit. One can tell this is happening by inspecting the logs: ``` 2024-09-16T13:17:16.509-0400 [DEBUG] turborepo_ui::tui::app: updating task list: ["docs#dev", "web#dev"] ... 2024-09-16T13:17:16.512-0400 [DEBUG] turborepo_ui::tui::app: finishing task web#dev ``` The TUI is receiving that `web#dev` finish event from the previous run which confuses the TUI as web#dev hasn't been started yet in this run. This appears to only happen for tasks that don't exit within a 500ms of receiving `SIGINT` and need to be forcibly killed. ### Testing Instructions Use `create-turbo` to create a basic repro. Change one of the dev scripts to have a long running `SIGINT` handler: ``` "dev": "trap 'sleep 5 && echo fin' SIGINT; next dev --turbo" ``` Observe that editing root `package.json` (just adding/changing `"description"` will do) while `turbo watch dev` is running results in a crash: Screenshot 2024-09-16 at 1 36 03 PM Checkout the changes in this PR and try the same thing. You should observe that `turbo_dev --skip-infer watch dev` no longer crashes on a root `package.json` change. Screenshot 2024-09-16 at 1 37 25 PM You can see that the `SIGINT` handler has not run as there is no `fin` displayed in the output on the restart. --- crates/turborepo-lib/src/run/watch.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/turborepo-lib/src/run/watch.rs b/crates/turborepo-lib/src/run/watch.rs index 7ba86ff5074a7..f72bd2b0b0c8b 100644 --- a/crates/turborepo-lib/src/run/watch.rs +++ b/crates/turborepo-lib/src/run/watch.rs @@ -337,7 +337,9 @@ impl WatchClient { { // Shut down the tasks for the run stopper.stop().await; - run_task.abort(); + // Run should exit shortly after we stop all child tasks, wait for it to finish + // to ensure all messages are flushed. + let _ = run_task.await; } if let Some(sender) = &self.ui_sender { let task_names = self.run.engine.tasks_with_command(&self.run.pkg_dep_graph);