Skip to content
File

Blob: src/worker/services/inbox/cleanup.ts

typescript66 lines
1import { and, asc, eq, inArray, lt } from "drizzle-orm";
2import { createDb, type Database } from "@/worker/db";
3import { emails, inboxes } from "@/worker/db/schema";
4import { createLogger } from "@/worker/logger";
5import { deleteStorageForEmails } from "@/worker/services/storage";
6import type { InboxRecord } from "@/worker/types";
7import { collectEmailIds } from "./queries";
8import { revokeInboxSessionToken } from "./session-store";
9import { EXPIRED_INBOX_CLEANUP_BATCH_SIZE } from "./shared";
10 
11const logger = createLogger("inbox-service");
12 
13export async function purgeEmailStorage(bucket: R2Bucket, emailIds: string[]) {
14 await deleteStorageForEmails(bucket, emailIds);
15}
16 
17export async function deleteEmailWithStorage(env: Env, emailId: string, db: Database) {
18 await purgeEmailStorage(env.STORAGE, [emailId]);
19 await db.delete(emails).where(eq(emails.id, emailId));
20}
21 
22export async function purgeInboxes(env: Env, targetInboxes: InboxRecord[], db: Database) {
23 if (targetInboxes.length === 0) {
24 return;
25 }
26 
27 const inboxIds = targetInboxes.map((inbox) => inbox.id);
28 const emailIds = await collectEmailIds(db, inboxIds);
29 
30 await purgeEmailStorage(env.STORAGE, emailIds);
31 await Promise.all(targetInboxes.map((inbox) => revokeInboxSessionToken(env, inbox.fullAddress)));
32 await db.delete(inboxes).where(inArray(inboxes.id, inboxIds));
33}
34 
35export async function cleanupExpiredInboxes(env: Env) {
36 const db = createDb(env.DB);
37 let deleted = 0;
38 
39 while (true) {
40 const expiredInboxes = await db.query.inboxes.findMany({
41 where: and(eq(inboxes.isPermanent, false), lt(inboxes.expiresAt, new Date())),
42 orderBy: [asc(inboxes.expiresAt), asc(inboxes.id)],
43 limit: EXPIRED_INBOX_CLEANUP_BATCH_SIZE,
44 });
45 
46 if (expiredInboxes.length === 0) {
47 break;
48 }
49 
50 await purgeInboxes(env, expiredInboxes, db);
51 
52 deleted += expiredInboxes.length;
53 
54 logger.info("cleanup_completed", "Deleted expired inbox batch", {
55 batchDeleted: expiredInboxes.length,
56 deleted,
57 });
58 
59 if (expiredInboxes.length < EXPIRED_INBOX_CLEANUP_BATCH_SIZE) {
60 break;
61 }
62 }
63 
64 return { deleted };
65}