Shun Miyazawa 1 год назад
Родитель
Сommit
f551ba7c37

+ 5 - 2
apps/app/src/features/openai/server/services/openai.ts

@@ -32,7 +32,7 @@ let isVectorStoreForPublicScopeExist = false;
 export interface IOpenaiService {
   getOrCreateThread(userId: string, vectorStoreId?: string, threadId?: string): Promise<OpenAI.Beta.Threads.Thread | undefined>;
   getOrCreateVectorStoreForPublicScope(): Promise<VectorStoreDocument>;
-  deleteExpiredThreads(limit: number): Promise<void>;
+  deleteExpiredThreads(limit: number, apiCallInterval: number): Promise<void>;
   createVectorStoreFile(pages: PageDocument[]): Promise<void>;
   deleteVectorStoreFile(pageId: Types.ObjectId): Promise<void>;
   rebuildVectorStoreAll(): Promise<void>;
@@ -78,7 +78,7 @@ class OpenaiService implements IOpenaiService {
     }
   }
 
-  public async deleteExpiredThreads(limit: number): Promise<void> {
+  public async deleteExpiredThreads(limit: number, apiCallInterval: number): Promise<void> {
     const expiredThreadRelations = await ThreadRelationModel.getExpiredThreadRelations(limit);
     if (expiredThreadRelations == null) {
       return;
@@ -90,6 +90,9 @@ class OpenaiService implements IOpenaiService {
         const deleteThreadResponse = await this.client.deleteThread(expiredThreadRelation.threadId);
         logger.debug('Delete thread', deleteThreadResponse);
         deletedThreadIds.push(expiredThreadRelation.threadId);
+
+        // sleep
+        await new Promise(resolve => setTimeout(resolve, apiCallInterval));
       }
       catch (err) {
         logger.error(err);

+ 13 - 11
apps/app/src/features/openai/server/services/thread-deletion-cron.ts

@@ -5,17 +5,20 @@ import loggerFactory from '~/utils/logger';
 
 import { getOpenaiService, type IOpenaiService } from './openai';
 
-
 const logger = loggerFactory('growi:service:thread-deletion-cron');
 
-const DELETE_LIMIT = 100;
-
 class ThreadDeletionCronService {
 
   cronJob: nodeCron.ScheduledTask;
 
   openaiService: IOpenaiService;
 
+  threadDeletionCronExpression: string;
+
+  threadDeletionBarchSize: number;
+
+  threadDeletionApiCallInterval: number;
+
   startCron(): void {
     const isAiEnabled = configManager.getConfig('crowi', 'app:aiEnabled');
     if (!isAiEnabled) {
@@ -28,23 +31,22 @@ class ThreadDeletionCronService {
     }
 
     this.openaiService = openaiService;
-
-    // Executed at 0 minutes of every hour
-    const cronSchedule = '0 * * * *';
+    this.threadDeletionCronExpression = configManager.getConfig('crowi', 'openai:threadDeletionCronExpression');
+    this.threadDeletionBarchSize = configManager.getConfig('crowi', 'openai:threadDeletionBarchSize');
+    this.threadDeletionApiCallInterval = configManager.getConfig('crowi', 'openai:threadDeletionApiCallInterval');
 
     this.cronJob?.stop();
-    this.cronJob = this.generateCronJob(cronSchedule);
+    this.cronJob = this.generateCronJob();
     this.cronJob.start();
   }
 
   private async executeJob(): Promise<void> {
     // Must be careful of OpenAI's rate limit
-    // Delete up to 100 threads per hour
-    await this.openaiService.deleteExpiredThreads(DELETE_LIMIT);
+    await this.openaiService.deleteExpiredThreads(this.threadDeletionBarchSize, this.threadDeletionApiCallInterval);
   }
 
-  private generateCronJob(cronSchedule: string) {
-    return nodeCron.schedule(cronSchedule, async() => {
+  private generateCronJob() {
+    return nodeCron.schedule(this.threadDeletionCronExpression, async() => {
       try {
         await this.executeJob();
       }

+ 18 - 0
apps/app/src/server/service/config-loader.ts

@@ -801,6 +801,24 @@ const ENV_VAR_NAME_TO_CONFIG_INFO: Record<string, EnvConfig> = {
     type: ValueType.STRING,
     default: null,
   },
+  OPENAI_THREAD_DELETION_CRON_EXPRESSION: {
+    ns: 'crowi',
+    key: 'openai:threadDeletionCronExpression',
+    type: ValueType.STRING,
+    default: '0 * * * *', // every hour
+  },
+  OPENAI_THREAD_DELETION_BARCH_SIZE: {
+    ns: 'crowi',
+    key: 'openai:threadDeletionBarchSize',
+    type: ValueType.NUMBER,
+    default: 100,
+  },
+  OPENAI_THREAD_DELETION_API_CALL_INTERVAL: {
+    ns: 'crowi',
+    key: 'openai:threadDeletionApiCallInterval',
+    type: ValueType.NUMBER,
+    default: 36000, // msec
+  },
 };