Fullfører oppgave 17.6: Periodisk CAS tmp-opprydding

Legger til cleanup_tmp() i CasStore som sletter orphaned .tmp-filer
eldre enn 1 time. Disse oppstår når en skriveprosess krasjer midt i
en atomisk CAS-skriveoperasjon (skriv til tmp, rename til endelig path).

Ny bakgrunnsloop start_tmp_cleanup_loop() kjører hver time og fjerner
foreldede temp-filer. Følger samme mønster som pruning- og
disk-monitor-loopene.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
vegard 2026-03-18 05:57:10 +00:00
parent a3f8ca2dfa
commit ce56e31de2
3 changed files with 81 additions and 2 deletions

View file

@ -167,6 +167,83 @@ impl CasStore {
fn tmp_path(&self, hash: &str) -> PathBuf {
self.root.join("tmp").join(format!("{hash}.tmp"))
}
/// Slett temp-filer eldre enn `max_age` fra CAS tmp-katalogen.
/// Returnerer (antall slettet, bytes frigitt).
pub async fn cleanup_tmp(&self, max_age: std::time::Duration) -> std::io::Result<(usize, u64)> {
let tmp_dir = self.root.join("tmp");
if !tmp_dir.exists() {
return Ok((0, 0));
}
let mut deleted = 0usize;
let mut freed = 0u64;
let now = std::time::SystemTime::now();
let mut entries = tokio::fs::read_dir(&tmp_dir).await?;
while let Some(entry) = entries.next_entry().await? {
let meta = match entry.metadata().await {
Ok(m) => m,
Err(_) => continue,
};
if !meta.is_file() {
continue;
}
let modified = match meta.modified() {
Ok(t) => t,
Err(_) => continue,
};
let age = now.duration_since(modified).unwrap_or_default();
if age > max_age {
let size = meta.len();
if let Ok(()) = tokio::fs::remove_file(entry.path()).await {
deleted += 1;
freed += size;
tracing::debug!(
file = %entry.file_name().to_string_lossy(),
age_secs = age.as_secs(),
size,
"Slettet gammel temp-fil"
);
}
}
}
Ok((deleted, freed))
}
}
/// Start periodisk opprydding av CAS tmp-filer.
/// Kjører hver time, sletter filer eldre enn 1 time.
pub fn start_tmp_cleanup_loop(cas: CasStore) {
tokio::spawn(async move {
// Vent 45 sekunder etter oppstart
tokio::time::sleep(std::time::Duration::from_secs(45)).await;
tracing::info!("CAS tmp-opprydding startet (intervall: 1t, TTL: 1t)");
let max_age = std::time::Duration::from_secs(3600); // 1 time
let interval = std::time::Duration::from_secs(3600); // 1 time
loop {
match cas.cleanup_tmp(max_age).await {
Ok((deleted, freed)) => {
if deleted > 0 {
tracing::info!(
deleted,
freed_kb = freed / 1024,
"CAS tmp-opprydding: {} filer slettet, {} KB frigitt",
deleted,
freed / 1024,
);
}
}
Err(e) => {
tracing::warn!(error = %e, "CAS tmp-opprydding feilet");
}
}
tokio::time::sleep(interval).await;
}
});
}
#[cfg(test)]

View file

@ -171,6 +171,9 @@ async fn main() {
// Start nattlig bandwidth-parsing (oppgave 15.7)
bandwidth::start_bandwidth_parser(db.clone());
// Start periodisk CAS tmp-opprydding (oppgave 17.6)
cas::start_tmp_cleanup_loop(cas.clone());
let index_cache = publishing::new_index_cache();
let dynamic_page_cache = publishing::new_dynamic_page_cache();
let state = AppState { db, jwks, stdb, cas, index_cache, dynamic_page_cache, maintenance, priority_rules };

View file

@ -194,8 +194,7 @@ Ref: Kodegjennomgang av `b4c4bb8` (Lydstudio: lydredigering via FFmpeg).
- [x] 17.3 Fade/silence-logikk: fiks negativ fade-out start (clamp til 0), og adaptiv silence-margin (margin skal ikke overstige halve regionens varighet). Gi feilmelding ved ugyldige fade-varigheter.
- [x] 17.4 Frontend input-begrensninger: legg til `min`/`max` på alle tallfelter i OperationPanel (silenceThreshold, fadeMs, normTarget, compRatio). Hindre ugyldig input.
- [x] 17.5 Job-polling opprydding: rydd opp interval/timeout ved navigering bort fra studio-siden. Vis feilmelding etter N mislykkede polling-forsøk. Wrap metadata JSON.parse i try/catch.
- [~] 17.6 Temp-fil opprydding: legg til periodisk jobb i maskinrommet som sletter gamle temp-filer i CAS tmp-katalog. Bruk `/tmp` eller sett TTL.
> Påbegynt: 2026-03-18T05:54
- [x] 17.6 Temp-fil opprydding: legg til periodisk jobb i maskinrommet som sletter gamle temp-filer i CAS tmp-katalog. Bruk `/tmp` eller sett TTL.
- [ ] 17.7 FFmpeg feilmeldinger til bruker: propager stderr fra FFmpeg-feil til frontend via strukturert feilrespons. Vis i RenderDialog.
## Fase 18: AI-verktøy (arbeidsflate)