Drop the spent DeadAir clean-up and keep not-due skips off live updates (#196, #197)

The clean-up of DeadAir's old copies probed for its table on every open, and on
Postgres each failed probe is an ERROR in the server's log: 120 an hour from the
healthcheck alone. Production ran it already and is the only database.

A scan sent a not-due skip for each of ~1,535 feeds into a broadcast of 1,024,
so a page slow to read lagged and dropped events: 443 counted in five hours.
Nothing listening uses them; the terminal and the log still get them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-11 20:12:22 +00:00
parent 0d930e75ee
commit 12fadbd0f8
4 changed files with 22 additions and 43 deletions

View File

@@ -99,22 +99,6 @@ async fn create_missing(orm: &sea_orm::DatabaseConnection) -> Result<()> {
let sql = "ALTER TABLE deadair_prefs ADD COLUMN pause_ms BIGINT";
orm.execute_unprepared(sql).await.with_context(|| sql.to_owned())?;
}
// DeadAir made a shortened copy of each file until it played the original through a
// playlist (#181). The copies go with their table, and the files are looked at again, which
// takes seconds each. Found only while the table is there, so nothing is written after.
let copies = Statement::from_string(orm.get_database_backend(), "SELECT path FROM deadair WHERE path IS NOT NULL");
if let Ok(rows) = orm.query_all_raw(copies).await {
for r in rows {
// Only DeadAir's own files, `name.deadair.mp3`: anything else would be someone's original.
if let Ok(path) = r.try_get::<String>("", "path")
&& path.contains(".deadair.")
{
let _ = std::fs::remove_file(&path);
}
}
// IF EXISTS: the healthcheck's `ipx status` may open the database at the same moment.
orm.execute_unprepared("DROP TABLE IF EXISTS deadair").await.context("dropping DeadAir's copies")?;
}
Ok(())
}
@@ -2489,29 +2473,6 @@ pub fn now() -> i64 {
mod tests {
use super::*;
#[tokio::test]
async fn deadair_drops_its_old_copies_once() {
let db = Db::memory().await.unwrap();
let dir = std::env::temp_dir().join(format!("ipx-deadair-old-{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
let (orig, copy) = (dir.join("a.mp3"), dir.join("a.deadair.mp3"));
std::fs::write(&orig, "original").unwrap();
std::fs::write(&copy, "copy").unwrap();
db.orm.execute_unprepared("CREATE TABLE deadair (enclosure_id BIGINT PRIMARY KEY, path TEXT)").await.unwrap();
for (id, path) in [(1, &copy), (2, &orig)] {
db.orm
.execute_unprepared(&format!("INSERT INTO deadair VALUES ({id}, '{}')", path.display()))
.await
.unwrap();
}
create_missing(&db.orm).await.unwrap();
assert!(!copy.exists(), "the copy goes");
assert!(orig.exists(), "a path that is not DeadAir's own is never removed");
assert!(db.orm.execute_unprepared("SELECT 1 FROM deadair").await.is_err(), "and the table");
create_missing(&db.orm).await.unwrap();
std::fs::remove_dir_all(&dir).unwrap();
}
#[tokio::test]
async fn deadair_looks_at_a_file_once_per_download_and_counts_an_episode_once() {
let db = Db::memory().await.unwrap();