@@ -655,19 +655,35 @@ async fn verify_batch<W: WriteColor>(
655655) -> anyhow:: Result < bool > {
656656 let mut has_errors = false ;
657657 if options. remote . is_some ( ) {
658- let results = stream:: iter ( files)
659- . map ( |file| async move {
660- let mut local_error_writer = Buffer :: no_color ( ) ;
661- let is_error = verify_bpl ( env, & mut local_error_writer, options, file) . await ;
662- ( local_error_writer, is_error)
663- } )
664- . buffer_unordered ( options. remote . as_ref ( ) . unwrap ( ) . concurrency )
665- . collect :: < Vec < _ > > ( )
666- . await ;
667-
668- for ( local_error_writer, is_error) in results {
669- error_writer. write_all ( & local_error_writer. into_inner ( ) ) ?;
670- if is_error? {
658+ // Separate files into remote and local batches. Files with run_on="local"
659+ // use blocking subprocess execution which would starve the tokio runtime
660+ // if run inside buffer_unordered, so they must be run sequentially.
661+ let ( local_files, remote_files) : ( Vec < _ > , Vec < _ > ) = files
662+ . into_iter ( )
663+ . partition ( |f| f. run_on . as_deref ( ) == Some ( RUN_ON_LOCAL ) ) ;
664+
665+ if !remote_files. is_empty ( ) {
666+ let results = stream:: iter ( remote_files)
667+ . map ( |file| async move {
668+ let mut local_error_writer = Buffer :: no_color ( ) ;
669+ let is_error = verify_bpl ( env, & mut local_error_writer, options, file) . await ;
670+ ( local_error_writer, is_error)
671+ } )
672+ . buffer_unordered ( options. remote . as_ref ( ) . unwrap ( ) . concurrency )
673+ . collect :: < Vec < _ > > ( )
674+ . await ;
675+
676+ for ( local_error_writer, is_error) in results {
677+ error_writer. write_all ( & local_error_writer. into_inner ( ) ) ?;
678+ if is_error? {
679+ has_errors = true ;
680+ }
681+ }
682+ }
683+
684+ for file in local_files {
685+ let is_error = verify_bpl ( env, error_writer, options, file) . await ?;
686+ if is_error {
671687 has_errors = true ;
672688 }
673689 }
0 commit comments