feat: implement scheduled cleanup job for expired data
This commit is contained in:
118
src/modules/system/cleanup.service.ts
Normal file
118
src/modules/system/cleanup.service.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
import { lootdrops, userTimers, userQuests } from "@/db/schema";
|
||||
import { eq, and, lt, isNull, sql } from "drizzle-orm";
|
||||
import { DrizzleClient } from "@/lib/DrizzleClient";
|
||||
import { AuroraClient } from "@/lib/BotClient";
|
||||
import { env } from "@/lib/env";
|
||||
import { config } from "@/lib/config";
|
||||
|
||||
export const cleanupService = {
|
||||
/**
|
||||
* Runs all cleanup tasks
|
||||
*/
|
||||
runAll: async () => {
|
||||
console.log("🧹 Starting system cleanup...");
|
||||
const stats = {
|
||||
lootdrops: 0,
|
||||
timers: 0,
|
||||
quests: 0
|
||||
};
|
||||
|
||||
try {
|
||||
stats.lootdrops = await cleanupService.cleanupLootdrops();
|
||||
stats.timers = await cleanupService.cleanupTimers();
|
||||
stats.quests = await cleanupService.cleanupQuests();
|
||||
|
||||
console.log(`✅ Cleanup finished. Stats:
|
||||
- Lootdrops: ${stats.lootdrops} removed
|
||||
- Timers: ${stats.timers} removed
|
||||
- Quests: ${stats.quests} cleaned`);
|
||||
} catch (error) {
|
||||
console.error("❌ Error during cleanup:", error);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Deletes unclaimed expired lootdrops
|
||||
*/
|
||||
cleanupLootdrops: async (): Promise<number> => {
|
||||
const now = new Date();
|
||||
const result = await DrizzleClient.delete(lootdrops)
|
||||
.where(and(
|
||||
lt(lootdrops.expiresAt, now),
|
||||
isNull(lootdrops.claimedBy)
|
||||
))
|
||||
.returning({ id: lootdrops.messageId });
|
||||
|
||||
return result.length;
|
||||
},
|
||||
|
||||
/**
|
||||
* Cleans up expired user timers and handles side effects (like role removal)
|
||||
*/
|
||||
cleanupTimers: async (): Promise<number> => {
|
||||
const now = new Date();
|
||||
let deletedCount = 0;
|
||||
|
||||
// 1. Specific handling for ACCESS timers (revoking roles etc)
|
||||
// This is migrated from scheduler.ts
|
||||
const expiredAccess = await DrizzleClient.query.userTimers.findMany({
|
||||
where: and(
|
||||
eq(userTimers.type, 'ACCESS'),
|
||||
lt(userTimers.expiresAt, now)
|
||||
)
|
||||
});
|
||||
|
||||
for (const timer of expiredAccess) {
|
||||
const meta = timer.metadata as any;
|
||||
const userIdStr = timer.userId.toString();
|
||||
|
||||
if (timer.key.startsWith('role_')) {
|
||||
try {
|
||||
const roleId = meta?.roleId || timer.key.replace('role_', '');
|
||||
const guildId = env.DISCORD_GUILD_ID;
|
||||
|
||||
if (guildId) {
|
||||
const guild = await AuroraClient.guilds.fetch(guildId);
|
||||
const member = await guild.members.fetch(userIdStr);
|
||||
await member.roles.remove(roleId);
|
||||
console.log(`👋 Removed temporary role ${roleId} from ${member.user.tag}`);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`Failed to remove role for user ${userIdStr}:`, err);
|
||||
}
|
||||
}
|
||||
|
||||
// Delete specifically this one
|
||||
await DrizzleClient.delete(userTimers)
|
||||
.where(and(
|
||||
eq(userTimers.userId, timer.userId),
|
||||
eq(userTimers.type, timer.type),
|
||||
eq(userTimers.key, timer.key)
|
||||
));
|
||||
deletedCount++;
|
||||
}
|
||||
|
||||
// 2. Bulk delete all other expired timers (COOLDOWN, EFFECT, etc)
|
||||
const result = await DrizzleClient.delete(userTimers)
|
||||
.where(lt(userTimers.expiresAt, now))
|
||||
.returning({ userId: userTimers.userId });
|
||||
|
||||
deletedCount += result.length;
|
||||
return deletedCount;
|
||||
},
|
||||
|
||||
/**
|
||||
* Deletes or archives old completed quests
|
||||
*/
|
||||
cleanupQuests: async (): Promise<number> => {
|
||||
const archiveDays = config.system.cleanup.questArchiveDays;
|
||||
const threshold = new Date();
|
||||
threshold.setDate(threshold.getDate() - archiveDays);
|
||||
|
||||
const result = await DrizzleClient.delete(userQuests)
|
||||
.where(lt(userQuests.completedAt, threshold))
|
||||
.returning({ userId: userQuests.userId });
|
||||
|
||||
return result.length;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user