From 024c14435c16334f4013c1ed2739c9f5c78f930e Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Sun, 29 Apr 2018 19:14:43 +0200 Subject: [PATCH] remove old temp files --- .../java/org/lucares/pdbui/CleanupThread.java | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 pdb-ui/src/main/java/org/lucares/pdbui/CleanupThread.java diff --git a/pdb-ui/src/main/java/org/lucares/pdbui/CleanupThread.java b/pdb-ui/src/main/java/org/lucares/pdbui/CleanupThread.java new file mode 100644 index 0000000..3959ae8 --- /dev/null +++ b/pdb-ui/src/main/java/org/lucares/pdbui/CleanupThread.java @@ -0,0 +1,95 @@ +package org.lucares.pdbui; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.attribute.FileTime; +import java.time.Instant; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.concurrent.CustomizableThreadFactory; +import org.springframework.stereotype.Component; + +@Component +public class CleanupThread implements DisposableBean, PropertyKeys { + + private static final Logger LOGGER = LoggerFactory.getLogger(CleanupThread.class); + + private static final class RemoveTempFiles implements Runnable { + + private final Path outputPath; + private final int cacheDurationInSeconds; + + public RemoveTempFiles(final Path outputPath, final int cacheDurationInSeconds) { + this.outputPath = outputPath; + this.cacheDurationInSeconds = cacheDurationInSeconds; + } + + @Override + public void run() { + + try { + Files.walk(outputPath)// + .filter(Files::isRegularFile)// + .filter(this::isStale)// + .forEach(RemoveTempFiles::delete); + } catch (final IOException | RuntimeException e) { + LOGGER.warn("failed to walk " + outputPath + ". Cannot delete stale files", e); + } + } + + private static void delete(final Path path) { + try { + LOGGER.debug("deleting stale file: " + path); + Files.delete(path); + } catch (final IOException e) { + LOGGER.warn("failed to delete stale file " + path, e); + } + } + + private boolean isStale(final Path path) { + final Instant maxAge = Instant.now().minusSeconds(cacheDurationInSeconds); + try { + final FileTime lastModifiedTime = Files.getLastModifiedTime(path); + final Instant lastModifiedInstant = lastModifiedTime.toInstant(); + return lastModifiedInstant.compareTo(maxAge) < 0; + } catch (final IOException e) { + LOGGER.warn("failed to get last modified time of " + path + ". Considering this file as stale.", e); + return true; + } + } + + } + + private final ScheduledExecutorService scheduledThreadPool; + + @Autowired + public CleanupThread(@Value("${" + PATH_GENERATED_IMAGES + "}") final String outputDir, + @Value("${" + CACHE_IMAGES_DURATION_SECONDS + ":" + CACHE_IMAGES_DURATION_SECONDS_DEFAULT + + "}") final int cacheDurationInSeconds) { + scheduledThreadPool = Executors.newScheduledThreadPool(1, new CustomizableThreadFactory("cleanup-")); + + final Path outputPath = Paths.get(outputDir); + scheduledThreadPool.scheduleWithFixedDelay(new RemoveTempFiles(outputPath, cacheDurationInSeconds), 1, 5, + TimeUnit.MINUTES); + } + + @Override + public void destroy() { + scheduledThreadPool.shutdown(); + try { + scheduledThreadPool.awaitTermination(10, TimeUnit.SECONDS); + } catch (final InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + +}