diff --git a/CHANGELOG.md b/CHANGELOG.md index f21f5a5..4065a09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- Checking for new episodes no longer waits up to 12 seconds each time on a clear-out of dead feeds from the Directory, which now runs once a day (#193). - All Subscriptions, and every item list, comes up faster, most of all the first time after a quiet spell: it took half a second to two (#188). ### Security diff --git a/src/main.rs b/src/main.rs index 26c8406..49431fd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -156,6 +156,9 @@ pub struct Ctx { /// Wakes DeadAir's maker when a show is turned on, so its copies start at once instead of /// at the next pass (#171). pub deadair: tokio::sync::Notify, + /// When the Directory was last cleared of dead feeds (`clean_directory`), 0 for not since + /// starting. + pub directory_cleaned: std::sync::atomic::AtomicI64, } /// A copy of the config to change, holding off every other change until `store_cfg` keeps it. @@ -348,6 +351,7 @@ async fn main() -> Result<()> { detach_torrents: is_daemon, retry: Default::default(), cfg_write: Default::default(), + directory_cleaned: Default::default(), deadair: Default::default(), }); @@ -1118,6 +1122,13 @@ async fn clean_directory(ctx: &Ctx) -> Result<()> { const DEAD: i64 = 30 * 86_400; const QUIET: i64 = 365 * 86_400; let now = db::now(); + // Once a day, for feeds dead a month or quiet a year: before every scan, its query took 1 to + // 12 s every few minutes, and the scans and downloads waited behind it (#193). + use std::sync::atomic::Ordering::Relaxed; + if now - ctx.directory_cleaned.load(Relaxed) < 86_400 { + return Ok(()); + } + ctx.directory_cleaned.store(now, Relaxed); let stale = ctx.db.stale_unsubscribed(now - DEAD, now - QUIET).await?; if stale.is_empty() { return Ok(()); @@ -2467,9 +2478,26 @@ mod tests { retry: Default::default(), cfg_write: Default::default(), deadair: Default::default(), + directory_cleaned: Default::default(), } } + #[tokio::test] + async fn dead_feeds_leave_the_directory_once_a_day_not_before_every_scan() { + let ctx = test_ctx(config::Config::default()).await; + let dead = |id: &str| format!("INSERT INTO feeds (id, url, error_since, managed) VALUES ('{id}', 'u-{id}', 100, false)"); + let listed = async || ctx.db.feed_urls().await.unwrap().into_iter().map(|(id, _)| id).collect::>(); + ctx.db.sql(&dead("a")).await.unwrap(); + clean_directory(&ctx).await.unwrap(); + assert!(listed().await.is_empty(), "the first pass since starting looks"); + ctx.db.sql(&dead("b")).await.unwrap(); + clean_directory(&ctx).await.unwrap(); + assert_eq!(listed().await, ["b"], "not again the same day (#193)"); + ctx.directory_cleaned.store(db::now() - 86_401, std::sync::atomic::Ordering::Relaxed); + clean_directory(&ctx).await.unwrap(); + assert!(listed().await.is_empty(), "a day on, it looks again"); + } + #[tokio::test] async fn a_removed_account_takes_the_feeds_only_it_read_with_it() { let ctx = test_ctx(config::Config::default()).await;