From 8a42c835a0dd1fcaa3475938d9442199d57acf75 Mon Sep 17 00:00:00 2001 From: Benedikt Peetz Date: Sun, 15 Jun 2025 18:23:54 +0200 Subject: feat(yt/update): Support grouped updates Rustpython currently does not use a garbage collector. Thus, every cyclic reference between Python objects results in a memory leak of these objects (as Rustpython uses (A)RCs). The only real way to workaround the memory leaks, is by restarting the whole process, and this `--grouped` flag seems to be the best solution for that. --- crates/yt/src/cli.rs | 6 ++++++ crates/yt/src/main.rs | 39 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 42 insertions(+), 3 deletions(-) (limited to 'crates') diff --git a/crates/yt/src/cli.rs b/crates/yt/src/cli.rs index 43df15f..c13693b 100644 --- a/crates/yt/src/cli.rs +++ b/crates/yt/src/cli.rs @@ -129,6 +129,12 @@ pub enum Command { /// The subscriptions to update subscriptions: Vec, + + /// Perform the updates in blocks. + /// + /// This works around the memory leaks in the default update invocation. + #[arg(short, long)] + grouped: bool, }, /// Manipulate subscription diff --git a/crates/yt/src/main.rs b/crates/yt/src/main.rs index e17f958..1affed9 100644 --- a/crates/yt/src/main.rs +++ b/crates/yt/src/main.rs @@ -13,7 +13,7 @@ // to print it anyways. #![allow(clippy::missing_errors_doc)] -use std::sync::Arc; +use std::{env::current_exe, sync::Arc}; use anyhow::{Context, Result, bail}; use app::App; @@ -161,6 +161,7 @@ async fn main() -> Result<()> { Command::Update { max_backlog, subscriptions, + grouped, } => { let all_subs = subscriptions::get(&app).await?; @@ -175,7 +176,39 @@ async fn main() -> Result<()> { let max_backlog = max_backlog.unwrap_or(app.config.update.max_backlog); - update::update(&app, max_backlog, subscriptions).await?; + if grouped { + let subs = { + if subscriptions.is_empty() { + all_subs.0.into_iter().map(|sub| sub.0).collect() + } else { + subscriptions + } + }; + + for chunk in subs.chunks(50) { + info!( + "$ yt update {}", + chunk + .iter() + .map(|sub_name| format!("{sub_name:#?}")) + .collect::>() + .join(" ") + ); + + let status = std::process::Command::new( + current_exe().context("Failed to get the current exe to re-execute")?, + ) + .arg("update") + .args(chunk) + .status()?; + + if !status.success() { + bail!("grouped yt update: Child process failed."); + } + } + } else { + update::update(&app, max_backlog, subscriptions).await?; + } } Command::Subscriptions { cmd } => match cmd { SubscriptionCommand::Add { name, url } => { @@ -236,7 +269,7 @@ async fn main() -> Result<()> { async fn dowa(arc_app: Arc) -> Result<()> { let max_cache_size = arc_app.config.download.max_cache_size; - info!("Max cache size: '{}'", max_cache_size); + info!("Max cache size: '{max_cache_size}'"); let arc_app_clone = Arc::clone(&arc_app); let download: JoinHandle<()> = tokio::spawn(async move { -- cgit 1.4.1