targo-backend/src/time-and-attendance/attachments/services/attachment-archival.service.ts
2025-12-04 15:00:36 -05:00

55 lines
2.1 KiB
TypeScript

import { Injectable } from "@nestjs/common";
import { Cron } from "@nestjs/schedule";
import { startOfYear } from "src/time-and-attendance/attachments/cas.util";
import { PrismaService } from "src/prisma/prisma.service";
@Injectable()
export class AttachmentArchivalService {
private readonly batch_size = Number(process.env.ARCHIVE_BATCH_SIZE || 1000);
private readonly cron_expression = process.env.ARCHIVE_CRON || '0 3 * * 1';
constructor(private readonly prisma: PrismaService) { }
@Cron(function (this: AttachmentArchivalService) { return this.cron_expression; } as any)
async runScheduled() {
await this.archiveCutoffToStartOfYear();
}
//archive everything before current year
async archiveCutoffToStartOfYear() {
const cutoff = startOfYear();
console.log(`Archival: cutoff=${cutoff.toISOString()} batch=${this.batch_size}`);
let moved = 0, total = 0, i = 0;
do {
moved = await this.archiveBatch(cutoff, this.batch_size);
total += moved;
i++;
if (moved > 0) console.log(`Batch #${i}: moved ${moved}`);
} while (moved === this.batch_size);
console.log(`Archival done: total moved : ${total}`);
return { moved: total };
}
//only moves table content to archive and not blobs.
private async archiveBatch(cutoff: Date, batch_size: number): Promise<number> {
const moved = await this.prisma.$executeRaw `
WITH moved AS (
DELETE FROM "attachments"
WHERE id IN (
SELECT id FROM "attachments"
WHERE created_at < ${cutoff}
ORDER BY id
LIMIT ${batch_size}
)
RETURNING id, sha256, owner_type, owner_id, original_name, status, retention_policy, created_by, created_at
)
INSERT INTO archive.attachments_archive
(id, sha256, owner_type, owner_id, original_name, status, retention_policy, created_by, created_at)
SELECT * FROM moved;`;
return Number(moved) || 0;
}
}