Skip to content

Commit 0335dfe

Browse files
committed
circus-evaluator: migrate evix 0.3.3 -> 1.0.2
Replace2 blocking `evaluate_cancellable` + `spawn_blocking` with the v1 async `Session::open(config).await?` + `session.stream()` drain loop. Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I6d77fd62f962d4b2ad9c7f42d8de44356a6a6964
1 parent a0992d1 commit 0335dfe

4 files changed

Lines changed: 120 additions & 92 deletions

File tree

Cargo.lock

Lines changed: 92 additions & 38 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ harmonia-store-path-info = { git = "https://github.com/nix-community/harmo
140140
harmonia-utils-hash = { git = "https://github.com/nix-community/harmonia.git", rev = "12c6742560dd1ba1e66f5cc2f04cabd4e99ae754" }
141141

142142
# evix, in-process Nix evaluator (nix-eval-jobs replacement) driven as a library.
143-
evix = { version = "0.3.3", features = [ "flake" ] }
143+
evix = { version = "1.0.2", features = [ "flake" ] }
144144

145145
# Workspace Clippy lints. All workspace crates must inherit them in individual
146146
# manifests for subcrates. The below list is a rather pedantic list of lints

crates/evaluator/src/nix.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ async fn evaluate_flake(
320320
show_input_drvs: true,
321321
override_inputs,
322322
nix_options: policy.nix_options(),
323+
..evix::Config::default()
323324
};
324325

325326
eval_command::run_eval(evix_config, timeout, "flake").await
@@ -504,6 +505,7 @@ async fn evaluate_legacy(
504505
show_input_drvs: true,
505506
override_inputs: Vec::new(),
506507
nix_options: NixEvalPolicy::from(config).nix_options(),
508+
..evix::Config::default()
507509
};
508510

509511
eval_command::run_eval(evix_config, timeout, "legacy").await

crates/evaluator/src/nix/eval_command.rs

Lines changed: 25 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,11 @@
1-
use std::{
2-
sync::{
3-
Arc,
4-
Mutex,
5-
atomic::{AtomicBool, Ordering},
6-
},
7-
time::Duration,
8-
};
1+
use std::time::Duration;
92

103
use circus_common::{CiError, error::Result};
114
use circus_config::EvaluatorConfig;
5+
use futures::StreamExt as _;
126
use tokio::process::Command;
137

14-
use super::{EvalResult, NixJob, nix_job_from_derivation};
8+
use super::{EvalResult, nix_job_from_derivation};
159

1610
/// Nix evaluation settings derived from the evaluator configuration, forwarded
1711
/// to evix as `(key, value)` options.
@@ -100,52 +94,33 @@ pub(super) async fn run_eval(
10094
"Starting evix evaluation with Nix options"
10195
);
10296

103-
let collected: Arc<Mutex<(Vec<NixJob>, usize)>> =
104-
Arc::new(Mutex::new((Vec::new(), 0)));
105-
let cancel = Arc::new(AtomicBool::new(false));
97+
let session = evix::Session::open(config)
98+
.await
99+
.map_err(|e| evix_eval_failure(description, &format!("{e:#}")))?;
106100

107-
let sink_state = Arc::clone(&collected);
108-
let cancel_eval = Arc::clone(&cancel);
109-
let handle = tokio::task::spawn_blocking(move || {
110-
evix::evaluate_cancellable(&config, &cancel_eval, move |event| {
111-
match event {
101+
let collect = async move {
102+
let mut events = session.stream();
103+
let mut jobs = Vec::new();
104+
let mut error_count = 0usize;
105+
106+
while let Some(event) = events.next().await {
107+
match event.map_err(|e| evix_eval_failure(description, &format!("{e:#}")))? {
112108
evix::Event::Derivation(drv) => {
113-
sink_state
114-
.lock()
115-
.unwrap_or_else(std::sync::PoisonError::into_inner)
116-
.0
117-
.push(nix_job_from_derivation(drv));
109+
jobs.push(nix_job_from_derivation(&drv));
118110
},
119111
evix::Event::Error(err) => {
120112
tracing::warn!(job = %err.attr, "evix reported error: {}", err.error);
121-
sink_state
122-
.lock()
123-
.unwrap_or_else(std::sync::PoisonError::into_inner)
124-
.1 += 1;
113+
error_count += 1;
125114
},
126115
evix::Event::AttrSet { .. } => {},
127116
}
128-
Ok(())
129-
})
130-
});
131-
132-
match tokio::time::timeout(timeout, handle).await {
133-
Ok(joined) => {
134-
joined
135-
.map_err(|e| {
136-
CiError::NixEval(format!("evix evaluation task failed to join: {e}"))
137-
})?
138-
.map_err(|e| evix_eval_failure(description, &format!("{e:#}")))?;
117+
}
118+
Ok::<EvalResult, CiError>(EvalResult { jobs, error_count })
119+
};
139120

140-
let result = {
141-
let guard = collected
142-
.lock()
143-
.unwrap_or_else(std::sync::PoisonError::into_inner);
144-
EvalResult {
145-
jobs: guard.0.clone(),
146-
error_count: guard.1,
147-
}
148-
};
121+
match tokio::time::timeout(timeout, collect).await {
122+
Ok(result) => {
123+
let result = result?;
149124
if result.error_count > 0 {
150125
tracing::warn!(
151126
error_count = result.error_count,
@@ -157,13 +132,9 @@ pub(super) async fn run_eval(
157132
}
158133
Ok(result)
159134
},
160-
Err(_elapsed) => {
161-
// Ask the in-flight evaluation to stop; its workers exit cooperatively.
162-
cancel.store(true, Ordering::Relaxed);
163-
Err(CiError::Timeout(format!(
164-
"Nix evaluation timed out after {timeout:?}"
165-
)))
166-
},
135+
Err(_elapsed) => Err(CiError::Timeout(format!(
136+
"Nix evaluation timed out after {timeout:?}"
137+
))),
167138
}
168139
}
169140

@@ -352,6 +323,7 @@ mod policy_tests {
352323
show_input_drvs: false,
353324
override_inputs: Vec::new(),
354325
nix_options: NixEvalPolicy::from(&config).nix_options(),
326+
..evix::Config::default()
355327
};
356328

357329
assert_eq!(evix_config.nix_options, vec![

0 commit comments

Comments
 (0)