mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-15 17:16:16 +08:00
9677bdf50d
fix AI-408 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added a new field to workspaces to track the last time embeddings were checked. * Cleanup jobs for workspace embeddings now skip workspaces that haven't changed in over 30 days or have no embeddings, improving efficiency. * Cleanup jobs are now automatically triggered when a workspace is updated. * **Improvements** * Enhanced workspace selection for cleanup and indexing tasks to use more precise filters and batching. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
117 lines
3.3 KiB
TypeScript
117 lines
3.3 KiB
TypeScript
import { Injectable, Logger } from '@nestjs/common';
|
|
import { Cron, CronExpression } from '@nestjs/schedule';
|
|
|
|
import { JOB_SIGNAL, JobQueue, OneDay, OnJob } from '../../base';
|
|
import { Models } from '../../models';
|
|
|
|
const CLEANUP_EMBEDDING_JOB_BATCH_SIZE = 100;
|
|
|
|
declare global {
|
|
interface Jobs {
|
|
'copilot.session.cleanupEmptySessions': {};
|
|
'copilot.session.generateMissingTitles': {};
|
|
'copilot.workspace.cleanupTrashedDocEmbeddings': {
|
|
nextSid?: number;
|
|
};
|
|
}
|
|
}
|
|
|
|
@Injectable()
|
|
export class CopilotCronJobs {
|
|
private readonly logger = new Logger(CopilotCronJobs.name);
|
|
|
|
constructor(
|
|
private readonly models: Models,
|
|
private readonly jobs: JobQueue
|
|
) {}
|
|
|
|
async triggerCleanupTrashedDocEmbeddings() {
|
|
await this.jobs.add(
|
|
'copilot.workspace.cleanupTrashedDocEmbeddings',
|
|
{},
|
|
{ jobId: 'daily-copilot-cleanup-trashed-doc-embeddings' }
|
|
);
|
|
}
|
|
|
|
@Cron(CronExpression.EVERY_DAY_AT_MIDNIGHT)
|
|
async dailyCleanupJob() {
|
|
await this.jobs.add(
|
|
'copilot.session.cleanupEmptySessions',
|
|
{},
|
|
{ jobId: 'daily-copilot-cleanup-empty-sessions' }
|
|
);
|
|
|
|
await this.jobs.add(
|
|
'copilot.session.generateMissingTitles',
|
|
{},
|
|
{ jobId: 'daily-copilot-generate-missing-titles' }
|
|
);
|
|
|
|
await this.jobs.add(
|
|
'copilot.workspace.cleanupTrashedDocEmbeddings',
|
|
{},
|
|
{ jobId: 'daily-copilot-cleanup-trashed-doc-embeddings' }
|
|
);
|
|
}
|
|
|
|
async triggerGenerateMissingTitles() {
|
|
await this.jobs.add(
|
|
'copilot.session.generateMissingTitles',
|
|
{},
|
|
{ jobId: 'trigger-copilot-generate-missing-titles' }
|
|
);
|
|
}
|
|
|
|
@OnJob('copilot.session.cleanupEmptySessions')
|
|
async cleanupEmptySessions() {
|
|
const { removed, cleaned } =
|
|
await this.models.copilotSession.cleanupEmptySessions(
|
|
new Date(Date.now() - OneDay)
|
|
);
|
|
|
|
this.logger.log(
|
|
`Cleanup completed: ${removed} sessions deleted, ${cleaned} sessions marked as deleted`
|
|
);
|
|
}
|
|
|
|
@OnJob('copilot.session.generateMissingTitles')
|
|
async generateMissingTitles() {
|
|
const sessions = await this.models.copilotSession.toBeGenerateTitle();
|
|
|
|
for (const session of sessions) {
|
|
await this.jobs.add('copilot.session.generateTitle', {
|
|
sessionId: session.id,
|
|
});
|
|
}
|
|
this.logger.log(
|
|
`Scheduled title generation for ${sessions.length} sessions`
|
|
);
|
|
}
|
|
|
|
@OnJob('copilot.workspace.cleanupTrashedDocEmbeddings')
|
|
async cleanupTrashedDocEmbeddings(
|
|
params: Jobs['copilot.workspace.cleanupTrashedDocEmbeddings']
|
|
) {
|
|
const nextSid = params.nextSid ?? 0;
|
|
// only consider workspaces that cleared their embeddings more than 24 hours ago
|
|
const oneDayAgo = new Date(Date.now() - OneDay);
|
|
const workspaces = await this.models.workspace.list(
|
|
{ sid: { gt: nextSid }, lastCheckEmbeddings: { lt: oneDayAgo } },
|
|
{ id: true, sid: true },
|
|
CLEANUP_EMBEDDING_JOB_BATCH_SIZE
|
|
);
|
|
if (!workspaces.length) {
|
|
return JOB_SIGNAL.Done;
|
|
}
|
|
for (const { id: workspaceId } of workspaces) {
|
|
await this.jobs.add(
|
|
'copilot.embedding.cleanupTrashedDocEmbeddings',
|
|
{ workspaceId },
|
|
{ jobId: `cleanup-trashed-doc-embeddings-${workspaceId}` }
|
|
);
|
|
}
|
|
params.nextSid = workspaces[workspaces.length - 1].sid;
|
|
return JOB_SIGNAL.Repeat;
|
|
}
|
|
}
|