Просмотр исходного кода

execute cleanup in Promise.allSettled and batch delete PageBulkExportJobs

Futa Arai 1 год назад
Родитель
Сommit
2674ad24d8

+ 35 - 28
apps/app/src/features/page-bulk-export/server/service/page-bulk-export-job-cron.ts

@@ -1,3 +1,5 @@
+import type { HydratedDocument } from 'mongoose';
+
 import { SupportedAction } from '~/interfaces/activity';
 import { configManager } from '~/server/service/config-manager';
 import CronService from '~/server/service/cron';
@@ -42,17 +44,13 @@ class PageBulkExportJobCronService extends CronService {
       $or: Object.values(PageBulkExportJobInProgressStatus).map(status => ({ status })),
       createdAt: { $lt: new Date(Date.now() - exportJobExpirationSeconds * 1000) },
     });
-    for (const expiredExportJob of expiredExportJobs) {
-      try {
-        // eslint-disable-next-line no-await-in-loop
-        await pageBulkExportService?.notifyExportResult(expiredExportJob, SupportedAction.ACTION_PAGE_BULK_EXPORT_JOB_EXPIRED);
-      }
-      catch (err) {
-        logger.error(err);
-      }
-      // eslint-disable-next-line no-await-in-loop
-      await this.cleanUpAndDeleteBulkExportJob(expiredExportJob);
-    }
+
+    const cleanup = async(job: PageBulkExportJobDocument) => {
+      await pageBulkExportService?.cleanUpExportJobResources(job);
+      await pageBulkExportService?.notifyExportResult(job, SupportedAction.ACTION_PAGE_BULK_EXPORT_JOB_EXPIRED);
+    };
+
+    await this.cleanUpAndDeleteBulkExportJobs(expiredExportJobs, cleanup);
   }
 
   /**
@@ -64,17 +62,13 @@ class PageBulkExportJobCronService extends CronService {
       status: PageBulkExportJobStatus.completed,
       completedAt: { $lt: new Date(Date.now() - downloadExpirationSeconds * 1000) },
     });
-    for (const downloadExpiredExportJob of downloadExpiredExportJobs) {
-      try {
-        // eslint-disable-next-line no-await-in-loop
-        await this.crowi.attachmentService?.removeAttachment(downloadExpiredExportJob.attachment);
-      }
-      catch (err) {
-        logger.error(err);
-      }
-      // eslint-disable-next-line no-await-in-loop
-      await this.cleanUpAndDeleteBulkExportJob(downloadExpiredExportJob);
-    }
+
+    const cleanup = async(job: PageBulkExportJobDocument) => {
+      await pageBulkExportService?.cleanUpExportJobResources(job);
+      await this.crowi.attachmentService?.removeAttachment(job.attachment);
+    };
+
+    await this.cleanUpAndDeleteBulkExportJobs(downloadExpiredExportJobs, cleanup);
   }
 
   /**
@@ -82,15 +76,28 @@ class PageBulkExportJobCronService extends CronService {
    */
   async deleteFailedExportJobs() {
     const failedExportJobs = await PageBulkExportJob.find({ status: PageBulkExportJobStatus.failed });
-    for (const failedExportJob of failedExportJobs) {
-      // eslint-disable-next-line no-await-in-loop
-      await this.cleanUpAndDeleteBulkExportJob(failedExportJob);
+
+    if (pageBulkExportService != null) {
+      await this.cleanUpAndDeleteBulkExportJobs(failedExportJobs, pageBulkExportService.cleanUpExportJobResources);
     }
   }
 
-  async cleanUpAndDeleteBulkExportJob(pageBulkExportJob: PageBulkExportJobDocument) {
-    await pageBulkExportService?.cleanUpExportJobResources(pageBulkExportJob);
-    await pageBulkExportJob.delete();
+  async cleanUpAndDeleteBulkExportJobs(
+      pageBulkExportJobs: HydratedDocument<PageBulkExportJobDocument>[],
+      cleanup: (job: PageBulkExportJobDocument) => Promise<void>,
+  ): Promise<void> {
+    const results = await Promise.allSettled(pageBulkExportJobs.map(job => cleanup(job)));
+    results.forEach((result) => {
+      if (result.status === 'rejected') logger.error(result.reason);
+    });
+
+    // Only batch delete jobs which have been successfully cleaned up
+    // Cleanup failed jobs will be retried in the next cron execution
+    const cleanedUpJobs = pageBulkExportJobs.filter((_, index) => results[index].status === 'fulfilled');
+    if (cleanedUpJobs.length > 0) {
+      const cleanedUpJobIds = cleanedUpJobs.map(job => job._id);
+      await PageBulkExportJob.deleteMany({ _id: { $in: cleanedUpJobIds } });
+    }
   }
 
 }