aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-07-17 18:07:43 +0900
committernsfisis <nsfisis@gmail.com>2026-07-17 18:07:43 +0900
commite44085eb742cb14dff22de054ef19fe725a4e2c2 (patch)
tree219dbdee6cbfb70dd4015add8558a02026b86183 /crates/shirabe
parentc6b10bd024894f857bf35a8f84c5e273be6f860d (diff)
downloadphp-shirabe-e44085eb742cb14dff22de054ef19fe725a4e2c2.tar.gz
php-shirabe-e44085eb742cb14dff22de054ef19fe725a4e2c2.tar.zst
php-shirabe-e44085eb742cb14dff22de054ef19fe725a4e2c2.zip
refactor(loop): drive wait() promises concurrently via FuturesUnordered
Loop::wait already had the target signature and a TODO(phase-c-promise) marker noting it drove promises serially; swap the for-loop for FuturesUnordered so all promises are polled together instead of one at a time, keeping the "remember only the first error" semantics. This adds the first real use of the futures dependency (already present in Cargo.toml/Cargo.lock from earlier prep work, now finally consumed), so those lockfile/manifest changes land in this commit. Real overlap still doesn't happen yet: each promise (HttpDownloader::add/ add_copy etc.) resolves through a blocking bridge (curl_runtime()/ sync_executor::block_on) that fully occupies the thread until it settles, so this is groundwork for once a single top-level Runtime replaces those bridges. Updated the TODO(phase-c-promise) comment to reflect that.
Diffstat (limited to 'crates/shirabe')
-rw-r--r--crates/shirabe/Cargo.toml1
-rw-r--r--crates/shirabe/src/util/loop.rs21
2 files changed, 12 insertions, 10 deletions
diff --git a/crates/shirabe/Cargo.toml b/crates/shirabe/Cargo.toml
index 7ec9db82..00ce5211 100644
--- a/crates/shirabe/Cargo.toml
+++ b/crates/shirabe/Cargo.toml
@@ -15,6 +15,7 @@ anyhow.workspace = true
async-trait.workspace = true
base64.workspace = true
chrono.workspace = true
+futures.workspace = true
indexmap.workspace = true
jsonschema.workspace = true
md5.workspace = true
diff --git a/crates/shirabe/src/util/loop.rs b/crates/shirabe/src/util/loop.rs
index 4efd7707..c2fa3b08 100644
--- a/crates/shirabe/src/util/loop.rs
+++ b/crates/shirabe/src/util/loop.rs
@@ -2,6 +2,8 @@
use crate::util::HttpDownloader;
use crate::util::ProcessExecutor;
+use futures::StreamExt;
+use futures::stream::FuturesUnordered;
use shirabe_external_packages::symfony::console::helper::ProgressBar;
#[derive(Debug)]
@@ -44,25 +46,24 @@ impl Loop {
>,
_progress: Option<&mut ProgressBar>,
) -> anyhow::Result<()> {
+ let mut pending: FuturesUnordered<_> = promises.into_iter().collect();
let mut uncaught: Option<anyhow::Error> = None;
- // TODO(phase-c-promise): the asynchronous worker classes (HttpDownloader / ProcessExecutor)
- // run single-threaded for now, so the promises are consumed serially. Once the workers run
- // on a multi-thread runtime these futures should be driven concurrently instead of in order.
+ // TODO(phase-c-promise): promises are now polled concurrently via FuturesUnordered, but
+ // each individual future (HttpDownloader::add/add_copy etc.) still resolves through a
+ // blocking bridge (curl_runtime()/sync_executor::block_on), so real I/O overlap does not
+ // happen yet — the bridged future fully blocks the thread until it settles before the next
+ // one gets polled. That only changes once a single top-level Runtime replaces those bridges.
// The PHP progress bar is tied to the worker active-job count and is also deferred until then.
- for promise in promises {
- if let Err(e) = promise.await
+ while let Some(result) = pending.next().await {
+ if let Err(e) = result
&& uncaught.is_none()
{
uncaught = Some(e);
}
}
- if let Some(e) = uncaught {
- return Err(e);
- }
-
- Ok(())
+ uncaught.map_or(Ok(()), Err)
}
pub fn abort_jobs(&self) {