-
Notifications
You must be signed in to change notification settings - Fork 116
fix(pm): drain pipeline worker tasks #2844
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,8 @@ use std::path::PathBuf; | |
| use super::receiver::PipelineChannels; | ||
| use crate::util::cloner::{clone_package_once, wait_clone_if_pending}; | ||
| use crate::util::downloader::{download_to_cache, is_git_url}; | ||
| use crate::util::user_config::get_manifests_concurrency_limit_sync; | ||
| use tokio::task::JoinSet; | ||
|
|
||
| /// Pipeline worker handles for awaiting completion. | ||
| pub struct PipelineHandles { | ||
|
|
@@ -18,10 +20,26 @@ impl PipelineHandles { | |
| } | ||
| } | ||
|
|
||
| async fn join_next(join_set: &mut JoinSet<()>, worker_name: &str) { | ||
| if let Some(result) = join_set.join_next().await | ||
| && let Err(e) = result | ||
| { | ||
| tracing::debug!("{worker_name} task failed: {e}"); | ||
| } | ||
| } | ||
|
|
||
| async fn drain_tasks(join_set: &mut JoinSet<()>, worker_name: &str) { | ||
| while !join_set.is_empty() { | ||
| join_next(join_set, worker_name).await; | ||
| } | ||
| } | ||
|
|
||
| /// Start download and clone pipeline workers, returning handles to await completion. | ||
| pub fn start_workers(channels: PipelineChannels, cwd: PathBuf) -> PipelineHandles { | ||
| let download_handle = tokio::spawn(async move { | ||
| let mut rx = channels.download_rx; | ||
| let mut tasks = JoinSet::new(); | ||
| let max_in_flight = get_manifests_concurrency_limit_sync().max(1); | ||
| while let Some(info) = rx.recv().await { | ||
| let Some(tarball_url) = info.tarball_url else { | ||
| continue; | ||
|
|
@@ -39,14 +57,20 @@ pub fn start_workers(channels: PipelineChannels, cwd: PathBuf) -> PipelineHandle | |
| } | ||
| let name = info.name; | ||
| let version = info.version; | ||
| tokio::spawn(async move { | ||
| tasks.spawn(async move { | ||
| download_to_cache(&name, &version, &tarball_url).await; | ||
| }); | ||
|
Comment on lines
+60
to
62
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The result of tasks.spawn(async move {
if let Err(e) = download_to_cache(&name, &version, &tarball_url).await {
tracing::debug!("Pipeline download failed for {name}@{version}: {e:#}");
}
}); |
||
| if tasks.len() >= max_in_flight { | ||
| join_next(&mut tasks, "pipeline download").await; | ||
| } | ||
| } | ||
| drain_tasks(&mut tasks, "pipeline download").await; | ||
| }); | ||
|
|
||
| let clone_handle = tokio::spawn(async move { | ||
| let mut rx = channels.clone_rx; | ||
| let mut tasks = JoinSet::new(); | ||
| let max_in_flight = get_manifests_concurrency_limit_sync().max(1); | ||
| while let Some(msg) = rx.recv().await { | ||
| let Some(tarball_url) = msg.info.tarball_url else { | ||
| continue; | ||
|
|
@@ -55,15 +79,19 @@ pub fn start_workers(channels: PipelineChannels, cwd: PathBuf) -> PipelineHandle | |
| let version = msg.info.version; | ||
| let target = cwd.join(&msg.path); | ||
| let parent_path = msg.parent_path.map(|p| cwd.join(&p)); | ||
| tokio::spawn(async move { | ||
| tasks.spawn(async move { | ||
| if let Some(ref parent) = parent_path { | ||
| wait_clone_if_pending(&parent.to_string_lossy()).await; | ||
| } | ||
| if let Err(e) = clone_package_once(&name, &version, &tarball_url, &target).await { | ||
| tracing::debug!("Pipeline pre-clone failed for {name}@{version}: {e:#}"); | ||
| } | ||
| }); | ||
| if tasks.len() >= max_in_flight { | ||
| join_next(&mut tasks, "pipeline clone").await; | ||
| } | ||
| } | ||
| drain_tasks(&mut tasks, "pipeline clone").await; | ||
| }); | ||
|
|
||
| PipelineHandles { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current implementation of
join_nextlogs all task failures, including panics, at thedebuglevel and continues. This effectively implements recovery logic for panics, which violates the general rule that panics should be treated as unrecoverable bugs. If a subtask panics, it usually indicates a serious issue that should not be silently ignored or recovered from in a background worker.Consider checking if the error is a panic and propagating it to ensure the worker fails as expected.
References