111 lines
4.4 KiB
JavaScript
111 lines
4.4 KiB
JavaScript
const pool = require("../db/pool.js");
|
|
const env = process.env.NODE_ENV;
|
|
const tbData = env === 'production' ? 'tb_data' : '_test_tb_data';
|
|
|
|
async function runAutoClean() {
|
|
const client = await pool.connect();
|
|
try {
|
|
console.log("⏰ Running auto clean batch job...");
|
|
|
|
// 1. 글로벌 보관 정책 조회
|
|
const policyRes = await client.query("SELECT * FROM ver4.tb_system_policy WHERE policy_key = 'GLOBAL_DELETE_POLICY'");
|
|
if (policyRes.rows.length === 0 || !policyRes.rows[0].is_active) {
|
|
console.log("⏰ Auto clean policy is disabled or not found.");
|
|
return;
|
|
}
|
|
|
|
const { limit_file_count, limit_days } = policyRes.rows[0];
|
|
|
|
// 2. 삭제 대상 3단계 폴더 검색
|
|
// - is_folder = true 이고 depth = 3 이며 아직 삭제되지 않은 폴더
|
|
// - 하위의 유효 파일 개수가 limit_file_count 미만
|
|
// - last_folder_act_date 가 limit_days 일 이상 경과
|
|
const targetQuery = `
|
|
SELECT data_id, project_id, path1, path2, path3, last_folder_act_date
|
|
FROM ver4.${tbData} f
|
|
WHERE f.is_folder = true
|
|
AND f.data_depth = 3
|
|
AND f.is_removed = false
|
|
AND f.last_folder_act_date < NOW() - CAST($1 || ' days' AS INTERVAL)
|
|
AND (
|
|
SELECT COUNT(*)
|
|
FROM ver4.${tbData} files
|
|
WHERE files.project_id = f.project_id
|
|
AND files.path1 = f.path1
|
|
AND files.path2 = f.path2
|
|
AND files.path3 = f.path3
|
|
AND files.is_folder = false
|
|
AND files.is_removed = false
|
|
) < $2;
|
|
`;
|
|
const targets = await client.query(targetQuery, [limit_days, limit_file_count]);
|
|
|
|
console.log(`⏰ Found ${targets.rows.length} folders to clean up.`);
|
|
|
|
for (const folder of targets.rows) {
|
|
let success = true;
|
|
try {
|
|
await client.query('BEGIN');
|
|
|
|
// 폴더 자체 및 그 하위 파일/폴더들을 전부 Soft-Delete (is_removed = true)
|
|
const updateQuery = `
|
|
UPDATE ver4.${tbData}
|
|
SET is_removed = true,
|
|
mod_date = CURRENT_TIMESTAMP,
|
|
mod_user_id = 'SYSTEM'
|
|
WHERE project_id = $1
|
|
AND path1 = $2
|
|
AND path2 = $3
|
|
AND path3 = $4
|
|
AND is_removed = false;
|
|
`;
|
|
await client.query(updateQuery, [folder.project_id, folder.path1, folder.path2, folder.path3]);
|
|
|
|
await client.query('COMMIT');
|
|
} catch (err) {
|
|
await client.query('ROLLBACK');
|
|
console.error(`❌ Auto Clean Folder Error [Folder ID: ${folder.data_id}]:`, err.message);
|
|
success = false;
|
|
}
|
|
|
|
// 삭제 경로 조합 (/path1/path2/path3)
|
|
const cleanPath = `/${folder.path1}/${folder.path2}/${folder.path3}`;
|
|
const criteria = `보관수량 ${limit_file_count}개 미만 / 기한 ${limit_days}일 경과`;
|
|
|
|
// 로그 기록
|
|
await client.query(`
|
|
INSERT INTO ver4.tb_auto_clean_log (clean_date, project_id, clean_path, criteria_info, result_status)
|
|
VALUES (CURRENT_TIMESTAMP, $1, $2, $3, $4);
|
|
`, [folder.project_id, cleanPath, criteria, success ? 'SUCCESS' : 'FAILED']);
|
|
}
|
|
console.log("⏰ Auto clean batch job finished successfully.");
|
|
} catch (err) {
|
|
console.error("❌ Auto Clean Batch Error:", err);
|
|
} finally {
|
|
client.release();
|
|
}
|
|
}
|
|
|
|
// 매일 자정에 한 번 가동하는 타이머 등록 함수
|
|
function startScheduler() {
|
|
const now = new Date();
|
|
const target = new Date();
|
|
target.setHours(0, 0, 0, 0);
|
|
if (now > target) {
|
|
target.setDate(target.getDate() + 1);
|
|
}
|
|
const delay = target - now;
|
|
|
|
console.log(`⏰ Scheduler loaded. Next run in ${Math.floor(delay / 1000 / 60)} minutes.`);
|
|
setTimeout(async () => {
|
|
await runAutoClean();
|
|
// 실행 후 다음날 자정으로 다시 예약
|
|
startScheduler();
|
|
}, delay);
|
|
}
|
|
|
|
module.exports = {
|
|
start: startScheduler,
|
|
runNow: runAutoClean
|
|
};
|