Skip to content

Commit 51c8361

Browse files
chore(signals): prefactor (#9995)
### Description Prefactors: - moved signal listening to own crate - return signal received to subscribers - support streams instead of single futures for signal sources PR that prefactors the signals code to prepare for: - Subscribers getting all signals sent to `turbo` - Additional signal handlers to be sent transparently to children There are no behavior changes in this PR. I highly suggest reviewing each commit on its own. ### Testing Instructions Existing unit tests. Quick manual verification that existing `SIGINT` behavior remains the same: ``` $ turbo_dev watch build ... │ Finalizing page optimization . Collecting build traces . └────> × Watch interrupted due to signal ```
1 parent 301396d commit 51c8361

File tree

18 files changed

+152
-73
lines changed

18 files changed

+152
-73
lines changed

Cargo.lock

+10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ turborepo-repository = { path = "crates/turborepo-repository" }
6565
turborepo-ui = { path = "crates/turborepo-ui" }
6666
turborepo-unescape = { path = "crates/turborepo-unescape" }
6767
turborepo-scm = { path = "crates/turborepo-scm" }
68+
turborepo-signals = { path = "crates/turborepo-signals" }
6869
wax = { path = "crates/turborepo-wax" }
6970
turborepo-vercel-api = { path = "crates/turborepo-vercel-api" }
7071
turborepo-vercel-api-mock = { path = "crates/turborepo-vercel-api-mock" }

crates/turborepo-lib/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ turborepo-lockfiles = { workspace = true }
139139
turborepo-microfrontends = { workspace = true }
140140
turborepo-repository = { path = "../turborepo-repository" }
141141
turborepo-scm = { workspace = true }
142+
turborepo-signals = { workspace = true }
142143
turborepo-telemetry = { path = "../turborepo-telemetry" }
143144
turborepo-ui = { workspace = true }
144145
turborepo-unescape = { workspace = true }

crates/turborepo-lib/src/cli/error.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@ use itertools::Itertools;
44
use miette::Diagnostic;
55
use thiserror::Error;
66
use turborepo_repository::package_graph;
7+
use turborepo_signals::{listeners::get_signal, SignalHandler};
78
use turborepo_telemetry::events::command::CommandEventBuilder;
89
use turborepo_ui::{color, BOLD, GREY};
910

1011
use crate::{
11-
commands::{bin, generate, link, login, ls, prune, run::get_signal, CommandBase},
12+
commands::{bin, generate, link, login, ls, prune, CommandBase},
1213
daemon::DaemonError,
1314
query,
1415
rewrite_json::RewriteError,
1516
run,
1617
run::{builder::RunBuilder, watch},
17-
signal::SignalHandler,
1818
};
1919

2020
#[derive(Debug, Error, Diagnostic)]
@@ -78,7 +78,7 @@ pub async fn print_potential_tasks(
7878
base: CommandBase,
7979
telemetry: CommandEventBuilder,
8080
) -> Result<(), Error> {
81-
let signal = get_signal()?;
81+
let signal = get_signal().map_err(run::Error::from)?;
8282
let handler = SignalHandler::new(signal);
8383
let color_config = base.color_config;
8484

crates/turborepo-lib/src/commands/boundaries.rs

+3-7
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
1+
use turborepo_signals::{listeners::get_signal, SignalHandler};
12
use turborepo_telemetry::events::command::CommandEventBuilder;
23

3-
use crate::{
4-
cli,
5-
commands::{run::get_signal, CommandBase},
6-
run::builder::RunBuilder,
7-
signal::SignalHandler,
8-
};
4+
use crate::{cli, commands::CommandBase, run::builder::RunBuilder};
95

106
pub async fn run(base: CommandBase, telemetry: CommandEventBuilder) -> Result<i32, cli::Error> {
11-
let signal = get_signal()?;
7+
let signal = get_signal().map_err(crate::run::Error::from)?;
128
let handler = SignalHandler::new(signal);
139

1410
let run = RunBuilder::new(base)?

crates/turborepo-lib/src/commands/ls.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ use serde::Serialize;
55
use thiserror::Error;
66
use turbopath::AnchoredSystemPath;
77
use turborepo_repository::package_graph::{PackageName, PackageNode};
8+
use turborepo_signals::{listeners::get_signal, SignalHandler};
89
use turborepo_telemetry::events::command::CommandEventBuilder;
910
use turborepo_ui::{color, cprint, cprintln, ColorConfig, BOLD, BOLD_GREEN, GREY};
1011

1112
use crate::{
1213
cli,
1314
cli::OutputFormat,
14-
commands::{run::get_signal, CommandBase},
15+
commands::CommandBase,
1516
run::{builder::RunBuilder, Run},
16-
signal::SignalHandler,
1717
};
1818

1919
#[derive(Debug, Error, Diagnostic)]
@@ -115,7 +115,7 @@ pub async fn run(
115115
telemetry: CommandEventBuilder,
116116
output: Option<OutputFormat>,
117117
) -> Result<(), cli::Error> {
118-
let signal = get_signal()?;
118+
let signal = get_signal().map_err(crate::run::Error::from)?;
119119
let handler = SignalHandler::new(signal);
120120

121121
let run_builder = RunBuilder::new(base)?;

crates/turborepo-lib/src/commands/query.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ use camino::Utf8Path;
55
use miette::{Diagnostic, Report, SourceSpan};
66
use thiserror::Error;
77
use turbopath::AbsoluteSystemPathBuf;
8+
use turborepo_signals::{listeners::get_signal, SignalHandler};
89
use turborepo_telemetry::events::command::CommandEventBuilder;
910

1011
use crate::{
11-
commands::{run::get_signal, CommandBase},
12+
commands::CommandBase,
1213
query,
1314
query::{Error, RepositoryQuery},
1415
run::builder::RunBuilder,
15-
signal::SignalHandler,
1616
};
1717

1818
const SCHEMA_QUERY: &str = "query IntrospectionQuery {
@@ -161,7 +161,7 @@ pub async fn run(
161161
variables_path: Option<&Utf8Path>,
162162
include_schema: bool,
163163
) -> Result<i32, Error> {
164-
let signal = get_signal()?;
164+
let signal = get_signal().map_err(crate::run::Error::from)?;
165165
let handler = SignalHandler::new(signal);
166166

167167
let run_builder = RunBuilder::new(base)?

crates/turborepo-lib/src/commands/run.rs

+3-28
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,11 @@
1-
use std::{future::Future, sync::Arc};
1+
use std::sync::Arc;
22

33
use tracing::error;
4+
use turborepo_signals::{listeners::get_signal, SignalHandler};
45
use turborepo_telemetry::events::command::CommandEventBuilder;
56
use turborepo_ui::sender::UISender;
67

7-
use crate::{commands::CommandBase, run, run::builder::RunBuilder, signal::SignalHandler};
8-
9-
#[cfg(windows)]
10-
pub fn get_signal() -> Result<impl Future<Output = Option<()>>, run::Error> {
11-
let mut ctrl_c = tokio::signal::windows::ctrl_c().map_err(run::Error::SignalHandler)?;
12-
Ok(async move { ctrl_c.recv().await })
13-
}
14-
15-
#[cfg(not(windows))]
16-
pub fn get_signal() -> Result<impl Future<Output = Option<()>>, run::Error> {
17-
use tokio::signal::unix;
18-
let mut sigint =
19-
unix::signal(unix::SignalKind::interrupt()).map_err(run::Error::SignalHandler)?;
20-
let mut sigterm =
21-
unix::signal(unix::SignalKind::terminate()).map_err(run::Error::SignalHandler)?;
22-
23-
Ok(async move {
24-
tokio::select! {
25-
res = sigint.recv() => {
26-
res
27-
}
28-
res = sigterm.recv() => {
29-
res
30-
}
31-
}
32-
})
33-
}
8+
use crate::{commands::CommandBase, run, run::builder::RunBuilder};
349

3510
pub async fn run(base: CommandBase, telemetry: CommandEventBuilder) -> Result<i32, run::Error> {
3611
let signal = get_signal()?;

crates/turborepo-lib/src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ mod query;
3434
mod rewrite_json;
3535
mod run;
3636
mod shim;
37-
mod signal;
3837
mod task_graph;
3938
mod task_hash;
4039
mod tracing;

crates/turborepo-lib/src/query/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@ use tokio::select;
2424
use turbo_trace::TraceError;
2525
use turbopath::AbsoluteSystemPathBuf;
2626
use turborepo_repository::{change_mapper::AllPackageChangeReason, package_graph::PackageName};
27+
use turborepo_signals::SignalHandler;
2728

2829
use crate::{
2930
get_version,
3031
query::{file::File, task::RepositoryTask},
3132
run::{builder::RunBuilder, Run},
32-
signal::SignalHandler,
3333
};
3434

3535
#[derive(Error, Debug, miette::Diagnostic)]

crates/turborepo-lib/src/run/builder.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use turborepo_repository::{
2020
package_json::PackageJson,
2121
};
2222
use turborepo_scm::SCM;
23+
use turborepo_signals::{SignalHandler, SignalSubscriber};
2324
use turborepo_telemetry::events::{
2425
command::CommandEventBuilder,
2526
generic::{DaemonInitStatus, GenericEventBuilder},
@@ -46,7 +47,6 @@ use crate::{
4647
process::ProcessManager,
4748
run::{scope, task_access::TaskAccess, task_id::TaskName, Error, Run, RunCache},
4849
shim::TurboState,
49-
signal::{SignalHandler, SignalSubscriber},
5050
turbo_json::{TurboJson, TurboJsonLoader, UIMode},
5151
DaemonConnector,
5252
};

crates/turborepo-lib/src/run/error.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ pub enum Error {
5252
#[error(transparent)]
5353
#[diagnostic(transparent)]
5454
Visitor(#[from] task_graph::VisitorError),
55-
#[error("Failed to register signal handler: {0}")]
56-
SignalHandler(std::io::Error),
55+
#[error(transparent)]
56+
SignalHandler(#[from] turborepo_signals::listeners::Error),
5757
#[error(transparent)]
5858
Daemon(#[from] daemon::DaemonError),
5959
#[error(transparent)]

crates/turborepo-lib/src/run/mod.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,17 @@ use std::{
2222

2323
pub use cache::{CacheOutput, ConfigCache, Error as CacheError, RunCache, TaskCache};
2424
use chrono::{DateTime, Local};
25+
use futures::StreamExt;
2526
use rayon::iter::ParallelBridge;
26-
use tokio::{select, task::JoinHandle};
27+
use tokio::{pin, select, task::JoinHandle};
2728
use tracing::{debug, instrument};
2829
use turbopath::{AbsoluteSystemPath, AbsoluteSystemPathBuf};
2930
use turborepo_api_client::{APIAuth, APIClient};
3031
use turborepo_ci::Vendor;
3132
use turborepo_env::EnvironmentVariableMap;
3233
use turborepo_repository::package_graph::{PackageGraph, PackageName, PackageNode};
3334
use turborepo_scm::SCM;
35+
use turborepo_signals::{listeners::get_signal, SignalHandler};
3436
use turborepo_telemetry::events::generic::GenericEventBuilder;
3537
use turborepo_ui::{
3638
cprint, cprintln, sender::UISender, tui, tui::TuiSender, wui::sender::WebUISender, ColorConfig,
@@ -45,7 +47,6 @@ use crate::{
4547
opts::Opts,
4648
process::ProcessManager,
4749
run::{global_hash::get_global_hash_inputs, summary::RunTracker, task_access::TaskAccess},
48-
signal::SignalHandler,
4950
task_graph::Visitor,
5051
task_hash::{get_external_deps_hash, get_internal_deps_hash, PackageInputsHashes},
5152
turbo_json::{TurboJson, TurboJsonLoader, UIMode},
@@ -336,8 +337,9 @@ impl Run {
336337
};
337338

338339
let interrupt = async {
339-
if let Ok(fut) = crate::commands::run::get_signal() {
340-
fut.await;
340+
if let Ok(fut) = get_signal() {
341+
pin!(fut);
342+
fut.next().await;
341343
} else {
342344
tracing::warn!("could not register ctrl-c handler");
343345
// wait forever

crates/turborepo-lib/src/run/watch.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ use thiserror::Error;
1010
use tokio::{select, sync::Notify, task::JoinHandle};
1111
use tracing::{instrument, trace, warn};
1212
use turborepo_repository::package_graph::PackageName;
13+
use turborepo_signals::{listeners::get_signal, SignalHandler};
1314
use turborepo_telemetry::events::command::CommandEventBuilder;
1415
use turborepo_ui::sender::UISender;
1516

1617
use crate::{
17-
commands::{self, CommandBase},
18+
commands::CommandBase,
1819
daemon::{proto, DaemonConnectorError, DaemonError},
1920
get_version, opts,
2021
run::{self, builder::RunBuilder, scope::target_selector::InvalidSelectorError, Run},
21-
signal::SignalHandler,
2222
turbo_json::CONFIG_FILE,
2323
DaemonConnector, DaemonPaths,
2424
};
@@ -115,7 +115,7 @@ impl WatchClient {
115115
experimental_write_cache: bool,
116116
telemetry: CommandEventBuilder,
117117
) -> Result<Self, Error> {
118-
let signal = commands::run::get_signal()?;
118+
let signal = get_signal().map_err(crate::run::Error::from)?;
119119
let handler = SignalHandler::new(signal);
120120

121121
if base.opts.repo_opts.root_turbo_json_path != base.repo_root.join_component(CONFIG_FILE) {

crates/turborepo-signals/Cargo.toml

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[package]
2+
name = "turborepo-signals"
3+
version = "0.1.0"
4+
edition = "2021"
5+
license = "MIT"
6+
7+
[dependencies]
8+
futures = "0.3.30"
9+
thiserror = { workspace = true }
10+
tokio = { workspace = true, features = ["full", "time"] }
11+
12+
[dev-dependencies]
13+
14+
[lints]
15+
workspace = true

0 commit comments

Comments
 (0)