Add a general-purpose scheduled task system with a persistent registry and status tracking, supporting background maintenance jobs such as orphaned blob reaping, expired upload cleanup, job event pruning, and TTS usage retention. Implement a new `scheduled_tasks` table, task engine, and handlers for each maintenance operation. Integrate an admin UI panel for monitoring, manual runs, and configuration of tasks. Update document and user data cleanup flows to delegate shared blob and preview deletion to the scheduled reaper. Add Vercel cron integration for serverless environments. BREAKING CHANGE: Document and user storage cleanup now relies on background scheduled tasks for shared blob and preview deletion; immediate inline deletion is no longer performed.
41 lines
1.4 KiB
TypeScript
41 lines
1.4 KiB
TypeScript
import { and, eq } from 'drizzle-orm';
|
|
import { db } from '@/db';
|
|
import { documents } from '@/db/schema';
|
|
import { deleteDocumentTtsSegmentCache } from '@/lib/server/tts/segments-cache';
|
|
import { hashForLog, serverLogger } from '@/lib/server/logger';
|
|
import { logDegraded } from '@/lib/server/errors/logging';
|
|
|
|
/**
|
|
* Remove a user's ownership of a document.
|
|
*
|
|
* Only the per-user TTS segment cache is cleaned inline (it is keyed by userId
|
|
* and not reachable afterwards). The shared, content-addressed document blob and
|
|
* its previews are reclaimed by the `reap-orphaned-blobs` task once no owner
|
|
* remains, so there is no inline blob deletion, last-owner check, or lock.
|
|
*/
|
|
export async function deleteOwnedDocument(input: {
|
|
userId: string;
|
|
documentId: string;
|
|
namespace: string | null;
|
|
}): Promise<boolean> {
|
|
const [removed] = await db
|
|
.delete(documents)
|
|
.where(and(
|
|
eq(documents.id, input.documentId),
|
|
eq(documents.userId, input.userId),
|
|
))
|
|
.returning();
|
|
if (!removed) return false;
|
|
|
|
await deleteDocumentTtsSegmentCache(input).catch((error) => {
|
|
logDegraded(serverLogger, {
|
|
event: 'documents.delete_owned.tts_cache_cleanup.failed',
|
|
msg: 'Failed to clean TTS segment cache after document deletion',
|
|
step: 'delete_document_tts_segment_cache',
|
|
context: { documentId: input.documentId, userIdHash: hashForLog(input.userId) },
|
|
error,
|
|
});
|
|
});
|
|
|
|
return true;
|
|
}
|