|
@@ -1,3 +1,6 @@
|
|
|
|
|
+import type { HydratedDocument } from 'mongoose';
|
|
|
|
|
+
|
|
|
|
|
+import { SupportedAction } from '~/interfaces/activity';
|
|
|
import { configManager } from '~/server/service/config-manager';
|
|
import { configManager } from '~/server/service/config-manager';
|
|
|
import CronService from '~/server/service/cron';
|
|
import CronService from '~/server/service/cron';
|
|
|
import loggerFactory from '~/utils/logger';
|
|
import loggerFactory from '~/utils/logger';
|
|
@@ -22,6 +25,10 @@ class PageBulkExportJobCronService extends CronService {
|
|
|
this.crowi = crowi;
|
|
this.crowi = crowi;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ override getCronSchedule(): string {
|
|
|
|
|
+ return configManager.getConfig('crowi', 'app:pageBulkExportJobCronSchedule');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
override async executeJob(): Promise<void> {
|
|
override async executeJob(): Promise<void> {
|
|
|
await this.deleteExpiredExportJobs();
|
|
await this.deleteExpiredExportJobs();
|
|
|
await this.deleteDownloadExpiredExportJobs();
|
|
await this.deleteDownloadExpiredExportJobs();
|
|
@@ -37,11 +44,13 @@ class PageBulkExportJobCronService extends CronService {
|
|
|
$or: Object.values(PageBulkExportJobInProgressStatus).map(status => ({ status })),
|
|
$or: Object.values(PageBulkExportJobInProgressStatus).map(status => ({ status })),
|
|
|
createdAt: { $lt: new Date(Date.now() - exportJobExpirationSeconds * 1000) },
|
|
createdAt: { $lt: new Date(Date.now() - exportJobExpirationSeconds * 1000) },
|
|
|
});
|
|
});
|
|
|
- for (const expiredExportJob of expiredExportJobs) {
|
|
|
|
|
- pageBulkExportService?.pageBulkExportJobStreamManager?.destroyJobStream(expiredExportJob._id);
|
|
|
|
|
- // 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);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -53,17 +62,13 @@ class PageBulkExportJobCronService extends CronService {
|
|
|
status: PageBulkExportJobStatus.completed,
|
|
status: PageBulkExportJobStatus.completed,
|
|
|
completedAt: { $lt: new Date(Date.now() - downloadExpirationSeconds * 1000) },
|
|
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);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -71,15 +76,28 @@ class PageBulkExportJobCronService extends CronService {
|
|
|
*/
|
|
*/
|
|
|
async deleteFailedExportJobs() {
|
|
async deleteFailedExportJobs() {
|
|
|
const failedExportJobs = await PageBulkExportJob.find({ status: PageBulkExportJobStatus.failed });
|
|
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 } });
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
}
|
|
}
|