n8n
Version:
n8n Workflow Automation Tool
150 lines • 7.24 kB
JavaScript
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PruningService = void 0;
const typedi_1 = require("typedi");
const n8n_core_1 = require("n8n-core");
const constants_1 = require("../constants");
const config_1 = __importDefault(require("../config"));
const execution_repository_1 = require("../databases/repositories/execution.repository");
const Logger_1 = require("../Logger");
const n8n_workflow_1 = require("n8n-workflow");
const OnShutdown_1 = require("../decorators/OnShutdown");
const orchestration_service_1 = require("./orchestration.service");
let PruningService = class PruningService {
constructor(logger, instanceSettings, executionRepository, binaryDataService, orchestrationService) {
this.logger = logger;
this.instanceSettings = instanceSettings;
this.executionRepository = executionRepository;
this.binaryDataService = binaryDataService;
this.orchestrationService = orchestrationService;
this.hardDeletionBatchSize = 100;
this.rates = {
softDeletion: config_1.default.getEnv('executions.pruneDataIntervals.softDelete') * constants_1.TIME.MINUTE,
hardDeletion: config_1.default.getEnv('executions.pruneDataIntervals.hardDelete') * constants_1.TIME.MINUTE,
};
this.isShuttingDown = false;
}
init() {
const { isLeader, isMultiMainSetupEnabled } = this.orchestrationService;
if (isLeader)
this.startPruning();
if (isMultiMainSetupEnabled) {
this.orchestrationService.multiMainSetup.on('leader-takeover', () => this.startPruning());
this.orchestrationService.multiMainSetup.on('leader-stepdown', () => this.stopPruning());
}
}
isPruningEnabled() {
if (!config_1.default.getEnv('executions.pruneData') ||
constants_1.inTest ||
config_1.default.get('generic.instanceType') !== 'main') {
return false;
}
if (config_1.default.getEnv('multiMainSetup.enabled') &&
config_1.default.getEnv('generic.instanceType') === 'main' &&
this.instanceSettings.isFollower) {
return false;
}
return true;
}
startPruning() {
if (!this.isPruningEnabled())
return;
if (this.isShuttingDown) {
this.logger.warn('[Pruning] Cannot start pruning while shutting down');
return;
}
this.logger.debug('[Pruning] Starting soft-deletion and hard-deletion timers');
this.setSoftDeletionInterval();
this.scheduleHardDeletion();
}
stopPruning() {
if (!this.isPruningEnabled())
return;
this.logger.debug('[Pruning] Removing soft-deletion and hard-deletion timers');
clearInterval(this.softDeletionInterval);
clearTimeout(this.hardDeletionTimeout);
}
setSoftDeletionInterval(rateMs = this.rates.softDeletion) {
const when = [rateMs / constants_1.TIME.MINUTE, 'min'].join(' ');
this.softDeletionInterval = setInterval(async () => await this.softDeleteOnPruningCycle(), this.rates.softDeletion);
this.logger.debug(`[Pruning] Soft-deletion scheduled every ${when}`);
}
scheduleHardDeletion(rateMs = this.rates.hardDeletion) {
const when = [rateMs / constants_1.TIME.MINUTE, 'min'].join(' ');
this.hardDeletionTimeout = setTimeout(() => {
this.hardDeleteOnPruningCycle()
.then((rate) => this.scheduleHardDeletion(rate))
.catch((error) => {
this.scheduleHardDeletion(1 * constants_1.TIME.SECOND);
const errorMessage = error instanceof Error
? error.message
: (0, n8n_workflow_1.jsonStringify)(error, { replaceCircularRefs: true });
this.logger.error('[Pruning] Failed to hard-delete executions', { errorMessage });
});
}, rateMs);
this.logger.debug(`[Pruning] Hard-deletion scheduled for next ${when}`);
}
async softDeleteOnPruningCycle() {
this.logger.debug('[Pruning] Starting soft-deletion of executions');
const result = await this.executionRepository.softDeletePrunableExecutions();
if (result.affected === 0) {
this.logger.debug('[Pruning] Found no executions to soft-delete');
return;
}
this.logger.debug('[Pruning] Soft-deleted executions', { count: result.affected });
}
shutdown() {
this.isShuttingDown = true;
this.stopPruning();
}
async hardDeleteOnPruningCycle() {
const ids = await this.executionRepository.hardDeleteSoftDeletedExecutions();
const executionIds = ids.map((o) => o.executionId);
if (executionIds.length === 0) {
this.logger.debug('[Pruning] Found no executions to hard-delete');
return this.rates.hardDeletion;
}
try {
this.logger.debug('[Pruning] Starting hard-deletion of executions', { executionIds });
await this.binaryDataService.deleteMany(ids);
await this.executionRepository.deleteByIds(executionIds);
this.logger.debug('[Pruning] Hard-deleted executions', { executionIds });
}
catch (error) {
this.logger.error('[Pruning] Failed to hard-delete executions', {
executionIds,
error: error instanceof Error ? error.message : `${error}`,
});
}
const isHighVolume = executionIds.length >= this.hardDeletionBatchSize;
return isHighVolume ? 1 * constants_1.TIME.SECOND : this.rates.hardDeletion;
}
};
exports.PruningService = PruningService;
__decorate([
(0, OnShutdown_1.OnShutdown)(),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], PruningService.prototype, "shutdown", null);
exports.PruningService = PruningService = __decorate([
(0, typedi_1.Service)(),
__metadata("design:paramtypes", [Logger_1.Logger,
n8n_core_1.InstanceSettings,
execution_repository_1.ExecutionRepository,
n8n_core_1.BinaryDataService,
orchestration_service_1.OrchestrationService])
], PruningService);
//# sourceMappingURL=pruning.service.js.map