Selaa lähdekoodia

fix: correct requeue functionality to prevent infinite file watching loops

- Add optional status parameter to createTask methods
- Requeued tasks now created with status 'requeued' instead of 'pending'
- Processing logic now correctly identifies manually requeued tasks
- Prevents infinite loops where requeued tasks were incorrectly skipped
- Fixes issue where requeue would cause continuous file change detection
Timothy Pomeroy 1 kuukausi sitten
vanhempi
commit
81fed9f967

+ 75 - 1
apps/service/src/app.controller.ts

@@ -166,6 +166,7 @@ export class AppController {
       output: fileRecord.output,
       preset: processingPreset,
       priority: 1, // Higher priority for manual requeues
+      status: 'requeued', // Mark as manually requeued
     });
 
     // Update file status to pending
@@ -271,6 +272,64 @@ export class AppController {
     return result;
   }
 
+  // Task maintenance endpoints
+  @Post('maintenance/tasks/cleanup')
+  cleanupTasks(
+    @Body('status') status?: string,
+    @Body('olderThanDays') olderThanDays?: number,
+  ) {
+    let result;
+    if (status) {
+      result = this.appService.cleanupTasksByStatus(status, olderThanDays);
+    } else if (olderThanDays) {
+      result = this.appService.cleanupOldTasks(olderThanDays);
+    } else {
+      // Default: cleanup completed and failed tasks older than 7 days
+      result = this.appService.cleanupTasksByStatus('completed', 7);
+      this.appService.cleanupTasksByStatus('failed', 7);
+      this.appService.cleanupTasksByStatus('skipped', 7);
+    }
+    this.eventsGateway.emitTaskUpdate({
+      type: 'task_cleanup',
+      status,
+      olderThanDays,
+    });
+    return result;
+  }
+
+  @Post('maintenance/tasks/archive')
+  archiveTasks(@Body('daysOld') daysOld: number = 30): { changes?: number } {
+    const result = this.appService.archiveOldTasks(daysOld);
+    this.eventsGateway.emitTaskUpdate({
+      type: 'task_archive',
+      daysOld,
+    });
+    return result;
+  }
+
+  @Post('maintenance/tasks/purge')
+  purgeAllTasks() {
+    const result = this.appService.purgeAllTasks();
+    this.eventsGateway.emitTaskUpdate({
+      type: 'task_purge',
+    });
+    return result;
+  }
+
+  @Get('maintenance/tasks/stats')
+  getTaskStats() {
+    return this.appService.getTaskStats();
+  }
+
+  @Post('maintenance/tasks/scheduled-cleanup')
+  runScheduledTaskCleanup() {
+    const result = this.appService.scheduledTaskCleanup();
+    this.eventsGateway.emitTaskUpdate({
+      type: 'scheduled_task_cleanup',
+    });
+    return result;
+  }
+
   @Get('config/settings')
   getSettings(
     @Query('key') key?: string,
@@ -332,7 +391,7 @@ export class AppController {
   }
 
   @Post('watcher/stop')
-  stopWatcher() {
+  async stopWatcher() {
     return this.appService.stopWatcher();
   }
 
@@ -374,6 +433,11 @@ export class AppController {
     return this.appService.updateQueueSettings(settings);
   }
 
+  @Get('tasks/processing-status')
+  getTaskProcessingStatus() {
+    return this.appService.taskProcessingStatus();
+  }
+
   @Get('tasks/:id')
   getTaskById(@Param('id') id: string) {
     return this.appService.getTaskById(parseInt(id));
@@ -383,4 +447,14 @@ export class AppController {
   deleteTask(@Param('id') id: string) {
     return this.appService.deleteTask(parseInt(id));
   }
+
+  @Post('tasks/start-processing')
+  startTaskProcessing() {
+    return this.appService.startTaskProcessing();
+  }
+
+  @Post('tasks/stop-processing')
+  stopTaskProcessing() {
+    return this.appService.stopTaskProcessing();
+  }
 }

+ 41 - 1
apps/service/src/app.service.ts

@@ -77,6 +77,7 @@ export class AppService {
     output: string;
     preset: string;
     priority?: number;
+    status?: string;
   }) {
     return this.taskQueue.createTask(taskData);
   }
@@ -145,7 +146,7 @@ export class AppService {
     return this.watcher.start(watches, options);
   }
 
-  stopWatcher() {
+  async stopWatcher() {
     return this.watcher.stop();
   }
 
@@ -153,6 +154,45 @@ export class AppService {
     return this.watcher.status();
   }
 
+  startTaskProcessing() {
+    return this.taskQueue.start();
+  }
+
+  stopTaskProcessing() {
+    return this.taskQueue.stop();
+  }
+
+  taskProcessingStatus() {
+    return this.taskQueue.getQueueStatus();
+  }
+
+  // Task maintenance methods
+  cleanupTasksByStatus(status: string, olderThanDays?: number) {
+    return this.db.deleteTasksByStatus(status, olderThanDays);
+  }
+
+  cleanupOldTasks(days: number) {
+    return this.db.deleteTasksOlderThan(days);
+  }
+
+  getTaskStats() {
+    return this.db.getTaskStats();
+  }
+
+  archiveOldTasks(daysOld: number = 30): { changes?: number } {
+    return this.db.archiveOldTasks(daysOld);
+  }
+
+  // Purge all tasks
+  purgeAllTasks() {
+    return this.db.purgeAllTasks();
+  }
+
+  // Scheduled maintenance
+  scheduledTaskCleanup() {
+    return this.maintenance.scheduledTaskCleanup();
+  }
+
   getHello(): string {
     return 'Hello World!';
   }

+ 2 - 1
apps/service/src/task-queue.service.ts

@@ -364,6 +364,7 @@ export class TaskQueueService implements OnModuleInit {
     output: string;
     preset: string;
     priority?: number;
+    status?: string;
   }) {
     // Check if file already exists in database
     const existingFile = this.db.findFile(taskData.dataset, taskData.input);
@@ -379,7 +380,7 @@ export class TaskQueueService implements OnModuleInit {
     // Create task
     const task = this.db.createTask({
       type: 'handbrake',
-      status: 'pending',
+      status: taskData.status || 'pending',
       dataset: taskData.dataset,
       input: taskData.input,
       output: taskData.output,