Merge pull request #50 from fuckdywl/master close #49

Optimize email cleanup and add database indexes
This commit is contained in:
BeilunYang
2025-05-22 23:08:01 +08:00
committed by GitHub
2 changed files with 22 additions and 46 deletions

View File

@@ -1,4 +1,4 @@
import { integer, sqliteTable, text, primaryKey, uniqueIndex } from "drizzle-orm/sqlite-core"
import { integer, sqliteTable, text, primaryKey, uniqueIndex, index } from "drizzle-orm/sqlite-core"
import type { AdapterAccountType } from "next-auth/adapters"
import { relations } from 'drizzle-orm';
@@ -46,7 +46,9 @@ export const emails = sqliteTable("email", {
.notNull()
.$defaultFn(() => new Date()),
expiresAt: integer("expires_at", { mode: "timestamp_ms" }).notNull(),
})
}, (table) => ({
expiresAtIdx: index("email_expires_at_idx").on(table.expiresAt),
}))
export const messages = sqliteTable("message", {
id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
@@ -60,7 +62,9 @@ export const messages = sqliteTable("message", {
receivedAt: integer("received_at", { mode: "timestamp_ms" })
.notNull()
.$defaultFn(() => new Date()),
})
}, (table) => ({
emailIdIdx: index("message_email_id_idx").on(table.emailId),
}))
export const webhooks = sqliteTable('webhook', {
id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()),

View File

@@ -6,9 +6,6 @@ const CLEANUP_CONFIG = {
// Whether to delete expired emails
DELETE_EXPIRED_EMAILS: true,
// Whether to delete messages from expired emails if not deleting the emails themselves
DELETE_MESSAGES_FROM_EXPIRED: true,
// Batch processing size
BATCH_SIZE: 100,
} as const
@@ -18,50 +15,25 @@ const main = {
const now = Date.now()
try {
// Find expired emails
const { results: expiredEmails } = await env.DB
.prepare(`
SELECT id
FROM email
WHERE expires_at < ?
LIMIT ?
`)
.bind(now, CLEANUP_CONFIG.BATCH_SIZE)
.all()
if (!expiredEmails?.length) {
console.log('No expired emails found')
if (!CLEANUP_CONFIG.DELETE_EXPIRED_EMAILS) {
console.log('Expired email deletion is disabled')
return
}
const expiredEmailIds = expiredEmails.map(email => email.id)
const placeholders = expiredEmailIds.map(() => '?').join(',')
if (CLEANUP_CONFIG.DELETE_EXPIRED_EMAILS) {
// First delete associated messages
await env.DB.prepare(`
DELETE FROM message
WHERE emailId IN (${placeholders})
`).bind(...expiredEmailIds).run()
// Then delete the emails
await env.DB.prepare(`
// Directly delete expired emails (messages will be cascade-deleted via foreign key constraint)
const result = await env.DB
.prepare(`
DELETE FROM email
WHERE id IN (${placeholders})
`).bind(...expiredEmailIds).run()
console.log(`Deleted ${expiredEmails.length} expired emails and their messages`)
} else if (CLEANUP_CONFIG.DELETE_MESSAGES_FROM_EXPIRED) {
// Only delete messages from expired emails
await env.DB.prepare(`
DELETE FROM message
WHERE emailId IN (${placeholders})
`).bind(...expiredEmailIds).run()
console.log(`Deleted messages from ${expiredEmails.length} expired emails`)
} else {
console.log('No cleanup actions performed (disabled in config)')
}
WHERE expires_at < ?
LIMIT ?
RETURNING id
`)
.bind(now, CLEANUP_CONFIG.BATCH_SIZE)
.run()
const deletedCount = result?.meta?.changes || 0
console.log(`Deleted ${deletedCount} expired emails and their associated messages`)
} catch (error) {
console.error('Failed to cleanup:', error)
throw error