1- use std:: {
2- sync:: {
3- Arc ,
4- Mutex ,
5- atomic:: { AtomicBool , Ordering } ,
6- } ,
7- time:: Duration ,
8- } ;
1+ use std:: time:: Duration ;
92
103use circus_common:: { CiError , error:: Result } ;
114use circus_config:: EvaluatorConfig ;
5+ use futures:: StreamExt as _;
126use 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