Skip to content

Commit 44049f9

Browse files
committed
fix: await all asset pipeline, even if some fail
When a pipeline step fails, the while loop will fail fast, but this will leave all other tasks still running in the background. Which might lead to the case where longer running tasks (like cargo build) run, while others abort the build. Having a case like this, might also lead to multiple cargo builds stacking up in the background. It also might lead to the case where a failure, due to a missing directory, will repeated, as repeated builds are triggered by the initial cargo build. Because only after the initial cargo build, the target folder will be ignored. But as the build fails fast, a new build will be triggered, as changes to the target folder are not yet ignored. Closes: #662
1 parent fb23677 commit 44049f9

File tree

1 file changed

+48
-15
lines changed

1 file changed

+48
-15
lines changed

src/pipelines/html.rs

Lines changed: 48 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
//! Source HTML pipelines.
22
3-
use std::path::PathBuf;
4-
use std::sync::Arc;
5-
3+
use crate::{
4+
config::{RtcBuild, WsProtocol},
5+
hooks::{spawn_hooks, wait_hooks},
6+
pipelines::{
7+
rust::RustApp, Attrs, PipelineStage, TrunkAsset, TrunkAssetPipelineOutput,
8+
TrunkAssetReference, TRUNK_ID,
9+
},
10+
processing::minify::minify_html,
11+
};
612
use anyhow::{ensure, Context, Result};
713
use futures_util::stream::{FuturesUnordered, StreamExt};
814
use nipper::Document;
15+
use std::path::PathBuf;
16+
use std::sync::Arc;
917
use tokio::fs;
1018
use tokio::runtime::Handle;
1119
use tokio::sync::mpsc;
12-
use tokio::task::JoinHandle;
13-
14-
use crate::config::{RtcBuild, WsProtocol};
15-
use crate::hooks::{spawn_hooks, wait_hooks};
16-
use crate::pipelines::rust::RustApp;
17-
use crate::pipelines::{
18-
Attrs, PipelineStage, TrunkAsset, TrunkAssetPipelineOutput, TrunkAssetReference, TRUNK_ID,
19-
};
20-
use crate::processing::minify::minify_html;
20+
use tokio::task::{JoinError, JoinHandle};
2121

2222
const PUBLIC_URL_MARKER_ATTR: &str = "data-trunk-public-url";
2323
const RELOAD_SCRIPT: &str = include_str!("../autoreload.js");
@@ -201,12 +201,45 @@ impl HtmlPipeline {
201201
target_html: &mut Document,
202202
mut pipelines: AssetPipelineHandles,
203203
) -> Result<()> {
204-
while let Some(asset_res) = pipelines.next().await {
204+
let mut errors = Vec::new();
205+
206+
/// finalize an asset pipeline with a single result
207+
async fn finalize(
208+
asset_res: std::result::Result<Result<TrunkAssetPipelineOutput>, JoinError>,
209+
target_html: &mut Document,
210+
) -> Result<()> {
205211
let asset = asset_res
206-
.context("failed to await asset finalization")?
212+
.context("failed to await asset pipeline")?
207213
.context("error from asset pipeline")?;
208-
asset.finalize(target_html).await?;
214+
215+
asset
216+
.finalize(target_html)
217+
.await
218+
.context("failed to finalize asset pipeline")?;
219+
220+
Ok(())
221+
}
222+
223+
// pull all results and store their errors
224+
while let Some(asset_res) = pipelines.next().await {
225+
if let Err(err) = finalize(asset_res, target_html).await {
226+
// store the error, but don't return, so that we can still await all others
227+
errors.push(err);
228+
}
229+
}
230+
231+
// now check for errors
232+
if let Some(first) = errors.pop() {
233+
// if we have some, fail with the first
234+
return Err(first.context(format!(
235+
"HTML build pipeline failed ({} errors), showing first",
236+
errors.len() + 1
237+
)));
209238
}
239+
240+
// return only once all pipeline steps have completed, so that we don't start a new build
241+
// while previous pipelines are still running
242+
210243
Ok(())
211244
}
212245

0 commit comments

Comments
 (0)