UNPKG

n8n

Version:

n8n Workflow Automation Tool

149 lines • 7.69 kB
"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); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ScheduleTriggerJobRegistrar = void 0; const backend_common_1 = require("@n8n/backend-common"); const config_1 = require("@n8n/config"); const di_1 = require("@n8n/di"); const scheduler_1 = require("@n8n/scheduler"); const n8n_workflow_1 = require("n8n-workflow"); const durable_job_provisioner_1 = require("../durable-job-provisioner"); const schedule_trigger_task_1 = require("./schedule-trigger-task"); let ScheduleTriggerJobRegistrar = class ScheduleTriggerJobRegistrar { constructor(logger, globalConfig, workflowsConfig, jobProvisioner) { this.logger = logger; this.jobProvisioner = jobProvisioner; this.intercepting = globalConfig.scheduler.enabled && workflowsConfig.useWorkflowPublicationService; this.defaultTimezone = globalConfig.generic.timezone; this.triggerNodeMode = globalConfig.scheduler.triggerNodeMode; this.allowSkipDurableScheduler = globalConfig.scheduler.allowSkipDurableScheduler; this.logger = this.logger.scoped('scheduler'); if (globalConfig.scheduler.enabled && !workflowsConfig.useWorkflowPublicationService) { this.logger.warn('N8N_SCHEDULER_ENABLED is set but the workflow publication service is disabled. The durable scheduler cannot take over schedule triggers, which keep using the legacy in-memory engine.'); } } interceptsNode(node) { if (!this.intercepting || node.type !== n8n_workflow_1.SCHEDULE_TRIGGER_NODE_TYPE || (this.allowSkipDurableScheduler && node.parameters?.skipDurableScheduler === true)) { return false; } return true; } createSession() { const pending = new Map(); return { createCollector: (workflow, node) => { const timezone = explicitTimezone(workflow); const collected = []; pending.set(pendingKey(workflow.id, node.id), collected); return { registerCron: ({ expression, recurrence, source }) => { const schedule = this.toSchedule(expression, timezone, recurrence, source); if (isDegenerateRecurrence(recurrence)) { (0, scheduler_1.validateSchedule)(schedule); this.logger.warn('Schedule trigger rule has a non-positive recurrence interval; it will never fire', { workflowId: workflow.id, nodeId: node.id }); collected.push({ schedule, firstRunAt: null }); } else { const computed = (0, scheduler_1.computeFirstRunAt)(withResolvedTimezone(schedule, this.defaultTimezone), new Date()); collected.push({ schedule, firstRunAt: computed }); } }, }; }, commit: async (workflowId, nodeId) => { const key = pendingKey(workflowId, nodeId); const collected = pending.get(key); if (collected !== undefined) { pending.delete(key); await this.provisionCollected(workflowId, nodeId, collected); } }, discard: (workflowId, nodeId) => { pending.delete(pendingKey(workflowId, nodeId)); }, }; } toSchedule(expression, timezone, recurrence, source) { if (this.triggerNodeMode === 'new' && source?.size !== undefined && (source.field === 'seconds' || source.field === 'minutes')) { const intervalSeconds = source.field === 'minutes' ? source.size * 60 : source.size; return { kind: 'interval', intervalSeconds }; } if (recurrence?.activated && recurrence.intervalSize >= 2) { return { kind: 'recurring_cron', cronExpression: expression, timezone, recurrenceUnit: recurrence.typeInterval, recurrenceSize: recurrence.intervalSize, }; } return { kind: 'cron', cronExpression: expression, timezone }; } async provisionCollected(workflowId, nodeId, collected) { const seen = new Map(); const desired = collected.map(({ schedule, firstRunAt }) => { const fingerprint = (0, scheduler_1.scheduleFingerprint)(schedule, firstRunAt !== null); const occurrence = seen.get(fingerprint) ?? 0; seen.set(fingerprint, occurrence + 1); return { name: `${workflowId}:${nodeId}:${fingerprint}:${occurrence}`, schedule, firstRunAt, }; }); const payload = { workflowId, nodeId }; const summary = await this.jobProvisioner.provision(workflowId, nodeId, schedule_trigger_task_1.SCHEDULE_TRIGGER_TASK_TYPE, { ...payload }, desired); this.logger.debug('Provisioned durable schedules for trigger node', { workflowId, nodeId, inserted: summary.inserted.length, redefined: summary.redefined.length, unchanged: summary.unchanged.length, removed: summary.removed.length, }); } async remove(workflowId, nodeId) { await this.jobProvisioner.deprovision(workflowId, nodeId); } async removeWorkflow(workflowId) { await this.jobProvisioner.deprovisionWorkflow(workflowId, schedule_trigger_task_1.SCHEDULE_TRIGGER_TASK_TYPE); } async removeWorkflowInTransaction(manager, workflowId) { await this.jobProvisioner.deprovisionWorkflowInTransaction(manager, workflowId, schedule_trigger_task_1.SCHEDULE_TRIGGER_TASK_TYPE); } }; exports.ScheduleTriggerJobRegistrar = ScheduleTriggerJobRegistrar; exports.ScheduleTriggerJobRegistrar = ScheduleTriggerJobRegistrar = __decorate([ (0, di_1.Service)(), __metadata("design:paramtypes", [backend_common_1.Logger, config_1.GlobalConfig, config_1.WorkflowsConfig, durable_job_provisioner_1.DurableJobProvisioner]) ], ScheduleTriggerJobRegistrar); const pendingKey = (workflowId, nodeId) => `${workflowId}:${nodeId}`; function explicitTimezone(workflow) { const timezone = workflow.settings?.timezone; return typeof timezone === 'string' && timezone !== '' && timezone !== 'DEFAULT' ? timezone : null; } function isDegenerateRecurrence(recurrence) { return recurrence?.activated === true && !recurrence.intervalSize; } function withResolvedTimezone(schedule, defaultTimezone) { if (schedule.kind === 'cron' || schedule.kind === 'recurring_cron') { return { ...schedule, timezone: schedule.timezone ?? defaultTimezone }; } return schedule; } //# sourceMappingURL=schedule-trigger-job-registrar.js.map