Skip to content

Instantly share code, notes, and snippets.

@panphora
Created June 18, 2024 21:19
Show Gist options
  • Save panphora/b24d2d0ddc8903c28fd900ba0694d038 to your computer and use it in GitHub Desktop.
Save panphora/b24d2d0ddc8903c28fd900ba0694d038 to your computer and use it in GitHub Desktop.
/*
Files in directories in "ephemeral" will be deleted
when they're older than the name specified by the directory
For example:
- Files in directory "min5" won't be older than 5 minutes
- Files in directory "min15" won't be older than 15 minutes
- Files in directory "day30" won't be older than 30 days
Time is fuzzy because the cron runs every 1min, so a file might
last 6 minutes in a directory called "min5"
No need to worry about the Node app always being on, as soon as
it starts back up, it will clear the older files within 1 min
*/
import { promises as fs } from "fs";
import path from "upath";
import cron from "node-cron";
import basedir from "#root/server-lib/basedir.js";
const targetDirectory = path.join(basedir, "ephemeral");
/**
* Sets up a single cron job that runs every 5 minutes for each sub-directory in the base directory,
* deleting files older than the age limit implied by the sub-directory name.
*/
async function setupCronJobForSubDirs(baseDir) {
cron.schedule('* * * * *', async () => {
try {
const dirs = await fs.readdir(baseDir);
for (const dir of dirs) {
const dirPath = path.join(baseDir, dir);
const ageLimit = parseDirNameToAgeLimit(dir);
if (dirPath.includes("/ephemeral/") && ageLimit !== null) {
await deleteOldFilesInDir(dirPath, ageLimit);
}
}
} catch (error) {
console.error(`Error in cron job: ${error}`);
}
});
console.log(`Cron job scheduled to run every 1 minute for directories in ${baseDir}`);
}
/**
* Converts a directory name to an age limit in milliseconds.
*/
function parseDirNameToAgeLimit(dirName) {
const match = dirName.match(/(min|hour|day)s?(\d+)/);
if (!match) return null;
const [, unit, value] = match;
let ageLimit;
switch (unit) {
case 'min':
ageLimit = parseInt(value, 10) * 60 * 1000; // milliseconds
break;
case 'hour':
ageLimit = parseInt(value, 10) * 60 * 60 * 1000; // milliseconds
break;
case 'day':
ageLimit = parseInt(value, 10) * 24 * 60 * 60 * 1000; // milliseconds
break;
default:
return null;
}
return ageLimit;
}
/**
* Deletes files older than a specified age limit within a directory.
*/
async function deleteOldFilesInDir(dirPath, ageLimit) {
try {
const files = await fs.readdir(dirPath);
const now = new Date();
for (const file of files) {
if (file.includes(".gitkeep")) {
return;
}
const filePath = path.join(dirPath, file);
const fileStats = await fs.stat(filePath);
const fileAge = now - new Date(fileStats.mtime);
if (fileAge > ageLimit) {
await fs.unlink(filePath);
console.log(`Deleted: ${filePath}`);
}
}
} catch (error) {
console.error(`Error in deleteOldFilesInDir: ${error}`);
}
}
// Initialize the cron job setup
setupCronJobForSubDirs(targetDirectory);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment