forked from jsl/video_editing_poc
The new cleanup job is in src/main/java/org/example/videoclips/operations/LocalArtifactCleanupJob.java. It runs on a schedule and removes expired files from:
- the FFmpeg input directory - the FFmpeg output directory - tmp/in-memory-storage - tmp/stub-output The schedule and retention window are now configurable through src/main/java/org/example/videoclips/config/VideoClippingProperties.java and src/main/resources/application.properties via: - video-clipping.cleanup.enabled - video-clipping.cleanup.local-artifact-poll-interval-ms - video-clipping.cleanup.local-artifact-retention-hours This closes the first retention slice from the plan on the worker side. It does not yet delete expired original videos or clips from real object storage, and it does not do database-driven retention policies. That would be the next cleanup step.
This commit is contained in:
parent
8f4804c2ab
commit
3d961f2adf
|
|
@ -36,6 +36,8 @@ public class VideoClippingProperties {
|
|||
|
||||
private final Ffmpeg ffmpeg = new Ffmpeg();
|
||||
|
||||
private final Cleanup cleanup = new Cleanup();
|
||||
|
||||
public long getMaxFileSizeBytes() {
|
||||
return maxFileSizeBytes;
|
||||
}
|
||||
|
|
@ -112,6 +114,10 @@ public class VideoClippingProperties {
|
|||
return ffmpeg;
|
||||
}
|
||||
|
||||
public Cleanup getCleanup() {
|
||||
return cleanup;
|
||||
}
|
||||
|
||||
public static class S3 {
|
||||
private String region = "us-east-1";
|
||||
private String bucket = "video-clipping-dev";
|
||||
|
|
@ -213,4 +219,38 @@ public class VideoClippingProperties {
|
|||
this.cleanupLocalFiles = cleanupLocalFiles;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Cleanup {
|
||||
private boolean enabled = true;
|
||||
|
||||
@Min(30000)
|
||||
private long localArtifactPollIntervalMs = 300000;
|
||||
|
||||
@Min(1)
|
||||
private int localArtifactRetentionHours = 24;
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public long getLocalArtifactPollIntervalMs() {
|
||||
return localArtifactPollIntervalMs;
|
||||
}
|
||||
|
||||
public void setLocalArtifactPollIntervalMs(long localArtifactPollIntervalMs) {
|
||||
this.localArtifactPollIntervalMs = localArtifactPollIntervalMs;
|
||||
}
|
||||
|
||||
public int getLocalArtifactRetentionHours() {
|
||||
return localArtifactRetentionHours;
|
||||
}
|
||||
|
||||
public void setLocalArtifactRetentionHours(int localArtifactRetentionHours) {
|
||||
this.localArtifactRetentionHours = localArtifactRetentionHours;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,67 @@
|
|||
package org.example.videoclips.operations;
|
||||
|
||||
import org.example.videoclips.config.VideoClippingProperties;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Component
|
||||
public class LocalArtifactCleanupJob {
|
||||
|
||||
private final VideoClippingProperties properties;
|
||||
|
||||
public LocalArtifactCleanupJob(VideoClippingProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Scheduled(fixedDelayString = "${video-clipping.cleanup.local-artifact-poll-interval-ms:300000}")
|
||||
public void cleanupLocalArtifacts() {
|
||||
if (!properties.getCleanup().isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Instant cutoff = Instant.now().minus(properties.getCleanup().getLocalArtifactRetentionHours(), ChronoUnit.HOURS);
|
||||
List<Path> roots = List.of(
|
||||
Path.of(properties.getFfmpeg().getInputDirectory()),
|
||||
Path.of(properties.getFfmpeg().getOutputDirectory()),
|
||||
Path.of("tmp/in-memory-storage"),
|
||||
Path.of("tmp/stub-output")
|
||||
);
|
||||
|
||||
for (Path root : roots) {
|
||||
cleanupRoot(root, cutoff);
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanupRoot(Path root, Instant cutoff) {
|
||||
if (!Files.exists(root)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try (Stream<Path> stream = Files.walk(root)) {
|
||||
stream.sorted(Comparator.reverseOrder())
|
||||
.filter(path -> !path.equals(root))
|
||||
.forEach(path -> deleteIfExpired(path, cutoff));
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteIfExpired(Path path, Instant cutoff) {
|
||||
try {
|
||||
FileTime lastModifiedTime = Files.getLastModifiedTime(path);
|
||||
if (lastModifiedTime.toInstant().isBefore(cutoff)) {
|
||||
Files.deleteIfExists(path);
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,3 +22,6 @@ video-clipping.ffmpeg.ffmpeg-binary=ffmpeg
|
|||
video-clipping.ffmpeg.input-directory=./tmp/ffmpeg-input
|
||||
video-clipping.ffmpeg.output-directory=./tmp/ffmpeg-output
|
||||
video-clipping.ffmpeg.cleanup-local-files=true
|
||||
video-clipping.cleanup.enabled=true
|
||||
video-clipping.cleanup.local-artifact-poll-interval-ms=300000
|
||||
video-clipping.cleanup.local-artifact-retention-hours=24
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
stub-clip-content-clip_f205e44bd8cb
|
||||
|
|
@ -0,0 +1 @@
|
|||
stub-clip-content-clip_0f9504972838
|
||||
|
|
@ -0,0 +1 @@
|
|||
stub-clip-content-clip_26599ec473ec
|
||||
Loading…
Reference in New Issue