feat(base): Add setting for frequency of automatic media cache cleanups

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This commit is contained in:
Kévin Commaille
2025-02-01 17:51:47 +01:00
parent 57919f5480
commit f7467ff57a

View File

@@ -79,6 +79,17 @@ pub struct MediaRetentionPolicy {
/// Defaults to 60 days.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub last_access_expiry: Option<Duration>,
/// The duration between two automatic media cache cleanups.
///
/// If this is set, a cleanup will be triggered after the given duration
/// is elapsed, at the next call to the media cache API. If this is set to
/// zero, each call to the media cache API will trigger a cleanup. If this
/// is `None`, cleanups will only occur if they are triggered manually.
///
/// Defaults to running cleanups daily.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub cleanup_frequency: Option<Duration>,
}
impl MediaRetentionPolicy {
@@ -91,7 +102,12 @@ impl MediaRetentionPolicy {
///
/// This means that all media will be cached and cleanups have no effect.
pub fn empty() -> Self {
Self { max_cache_size: None, max_file_size: None, last_access_expiry: None }
Self {
max_cache_size: None,
max_file_size: None,
last_access_expiry: None,
cleanup_frequency: None,
}
}
/// Set the maximum authorized size of the overall media cache, in bytes.
@@ -113,6 +129,12 @@ impl MediaRetentionPolicy {
self
}
/// Set the duration between two automatic media cache cleanups.
pub fn with_cleanup_frequency(mut self, duration: Option<Duration>) -> Self {
self.cleanup_frequency = duration;
self
}
/// Whether this policy has limitations.
///
/// If this policy has no limitations, a cleanup job would have no effect.
@@ -178,6 +200,24 @@ impl MediaRetentionPolicy {
.is_ok_and(|elapsed| elapsed >= max_duration)
})
}
/// Whether an automatic media cache cleanup should be triggered given the
/// time of the last cleanup.
///
/// # Arguments
///
/// * `current_time` - The current time.
///
/// * `last_cleanup_time` - The time of the last media cache cleanup.
pub fn should_clean_up(&self, current_time: SystemTime, last_cleanup_time: SystemTime) -> bool {
self.cleanup_frequency.is_some_and(|max_duration| {
current_time
.duration_since(last_cleanup_time)
// If this returns an error, the last cleanup time is newer than the current time.
// This shouldn't happen but in this case no cleanup job is needed.
.is_ok_and(|elapsed| elapsed >= max_duration)
})
}
}
impl Default for MediaRetentionPolicy {
@@ -189,6 +229,8 @@ impl Default for MediaRetentionPolicy {
max_file_size: Some(20 * 1024 * 1024),
// 60 days.
last_access_expiry: Some(Duration::from_secs(60 * 24 * 60 * 60)),
// 1 day.
cleanup_frequency: Some(Duration::from_secs(24 * 60 * 60)),
}
}
}
@@ -327,4 +369,36 @@ mod tests {
assert!(policy.has_content_expired(epoch_plus_60, last_access_time));
assert!(policy.has_content_expired(epoch_plus_120, last_access_time));
}
#[test]
fn test_media_retention_policy_cleanup_frequency() {
let epoch = SystemTime::UNIX_EPOCH;
let epoch_plus_60 = epoch + Duration::from_secs(60);
let epoch_plus_120 = epoch + Duration::from_secs(120);
let mut policy = MediaRetentionPolicy::empty();
assert!(!policy.should_clean_up(epoch_plus_60, epoch));
assert!(!policy.should_clean_up(epoch_plus_60, epoch_plus_60));
assert!(!policy.should_clean_up(epoch_plus_60, epoch_plus_120));
policy = policy.with_cleanup_frequency(Some(Duration::from_secs(0)));
assert!(policy.should_clean_up(epoch_plus_60, epoch));
assert!(policy.should_clean_up(epoch_plus_60, epoch_plus_60));
assert!(!policy.should_clean_up(epoch_plus_60, epoch_plus_120));
policy = policy.with_cleanup_frequency(Some(Duration::from_secs(30)));
assert!(policy.should_clean_up(epoch_plus_60, epoch));
assert!(!policy.should_clean_up(epoch_plus_60, epoch_plus_60));
assert!(!policy.should_clean_up(epoch_plus_60, epoch_plus_120));
policy = policy.with_cleanup_frequency(Some(Duration::from_secs(60)));
assert!(policy.should_clean_up(epoch_plus_60, epoch));
assert!(!policy.should_clean_up(epoch_plus_60, epoch_plus_60));
assert!(!policy.should_clean_up(epoch_plus_60, epoch_plus_120));
policy = policy.with_cleanup_frequency(Some(Duration::from_secs(90)));
assert!(!policy.should_clean_up(epoch_plus_60, epoch));
assert!(!policy.should_clean_up(epoch_plus_60, epoch_plus_60));
assert!(!policy.should_clean_up(epoch_plus_60, epoch_plus_120));
}
}