mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 10:02:05 +00:00
refactor(core): Centralize CronJob management (#10033)
This commit is contained in:
committed by
GitHub
parent
36b314d031
commit
09f2cf9eaf
@@ -1,10 +1,10 @@
|
||||
import type { CronExpression } from './Interfaces';
|
||||
import { randomInt } from './utils';
|
||||
|
||||
interface BaseTriggerTime<T extends string> {
|
||||
mode: T;
|
||||
}
|
||||
|
||||
type CronExpression = string;
|
||||
interface CustomTrigger extends BaseTriggerTime<'custom'> {
|
||||
cronExpression: CronExpression;
|
||||
}
|
||||
@@ -49,22 +49,24 @@ export type TriggerTime =
|
||||
| EveryWeek
|
||||
| EveryMonth;
|
||||
|
||||
const randomSecond = () => randomInt(60).toString();
|
||||
|
||||
export const toCronExpression = (item: TriggerTime): CronExpression => {
|
||||
if (item.mode === 'everyMinute') return `${randomSecond()} * * * * *`;
|
||||
if (item.mode === 'everyHour') return `${randomSecond()} ${item.minute} * * * *`;
|
||||
const randomSecond = randomInt(60);
|
||||
|
||||
if (item.mode === 'everyMinute') return `${randomSecond} * * * * *`;
|
||||
if (item.mode === 'everyHour') return `${randomSecond} ${item.minute} * * * *`;
|
||||
|
||||
if (item.mode === 'everyX') {
|
||||
if (item.unit === 'minutes') return `${randomSecond()} */${item.value} * * * *`;
|
||||
if (item.unit === 'hours') return `${randomSecond()} 0 */${item.value} * * *`;
|
||||
if (item.unit === 'minutes') return `${randomSecond} */${item.value} * * * *`;
|
||||
|
||||
const randomMinute = randomInt(60);
|
||||
if (item.unit === 'hours') return `${randomSecond} ${randomMinute} */${item.value} * * *`;
|
||||
}
|
||||
if (item.mode === 'everyDay') return `${randomSecond()} ${item.minute} ${item.hour} * * *`;
|
||||
if (item.mode === 'everyDay') return `${randomSecond} ${item.minute} ${item.hour} * * *`;
|
||||
if (item.mode === 'everyWeek')
|
||||
return `${randomSecond()} ${item.minute} ${item.hour} * * ${item.weekday}`;
|
||||
return `${randomSecond} ${item.minute} ${item.hour} * * ${item.weekday}`;
|
||||
|
||||
if (item.mode === 'everyMonth')
|
||||
return `${randomSecond()} ${item.minute} ${item.hour} ${item.dayOfMonth} * *`;
|
||||
return `${randomSecond} ${item.minute} ${item.hour} ${item.dayOfMonth} * *`;
|
||||
|
||||
return item.cronExpression.trim();
|
||||
return item.cronExpression.trim() as CronExpression;
|
||||
};
|
||||
|
||||
@@ -842,6 +842,14 @@ export interface SSHTunnelFunctions {
|
||||
getSSHClient(credentials: SSHCredentials): Promise<SSHClient>;
|
||||
}
|
||||
|
||||
type CronUnit = number | '*' | `*/${number}`;
|
||||
export type CronExpression =
|
||||
`${CronUnit} ${CronUnit} ${CronUnit} ${CronUnit} ${CronUnit} ${CronUnit}`;
|
||||
|
||||
export interface SchedulingFunctions {
|
||||
registerCron(cronExpression: CronExpression, onTick: () => void): void;
|
||||
}
|
||||
|
||||
export type NodeTypeAndVersion = {
|
||||
name: string;
|
||||
type: string;
|
||||
@@ -994,6 +1002,7 @@ export interface IPollFunctions
|
||||
helpers: RequestHelperFunctions &
|
||||
BaseHelperFunctions &
|
||||
BinaryHelperFunctions &
|
||||
SchedulingFunctions &
|
||||
JsonHelperFunctions;
|
||||
}
|
||||
|
||||
@@ -1014,6 +1023,7 @@ export interface ITriggerFunctions
|
||||
BaseHelperFunctions &
|
||||
BinaryHelperFunctions &
|
||||
SSHTunnelFunctions &
|
||||
SchedulingFunctions &
|
||||
JsonHelperFunctions;
|
||||
}
|
||||
|
||||
@@ -1436,14 +1446,10 @@ export type IParameterLabel = {
|
||||
size?: 'small' | 'medium';
|
||||
};
|
||||
|
||||
export interface IPollResponse {
|
||||
closeFunction?: CloseFunction;
|
||||
}
|
||||
|
||||
export interface ITriggerResponse {
|
||||
closeFunction?: CloseFunction;
|
||||
// To manually trigger the run
|
||||
manualTriggerFunction?: CloseFunction;
|
||||
manualTriggerFunction?: () => Promise<void>;
|
||||
// Gets added automatically at manual workflow runs resolves with
|
||||
// the first emitted data
|
||||
manualTriggerResponse?: Promise<INodeExecutionData[][]>;
|
||||
|
||||
@@ -58,6 +58,7 @@ import {
|
||||
STARTING_NODE_TYPES,
|
||||
} from './Constants';
|
||||
import { ApplicationError } from './errors/application.error';
|
||||
import { getGlobalState } from './GlobalState';
|
||||
|
||||
function dedupe<T>(arr: T[]): T[] {
|
||||
return [...new Set(arr)];
|
||||
@@ -94,6 +95,8 @@ export class Workflow {
|
||||
|
||||
settings: IWorkflowSettings;
|
||||
|
||||
readonly timezone: string;
|
||||
|
||||
// To save workflow specific static data like for example
|
||||
// ids of registered webhooks of nodes
|
||||
staticData: IDataObject;
|
||||
@@ -151,6 +154,7 @@ export class Workflow {
|
||||
});
|
||||
|
||||
this.settings = parameters.settings || {};
|
||||
this.timezone = this.settings.timezone ?? getGlobalState().defaultTimezone;
|
||||
|
||||
this.expression = new Expression(this);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { toCronExpression } from '@/Cron';
|
||||
import type { CronExpression } from '@/Interfaces';
|
||||
|
||||
describe('Cron', () => {
|
||||
describe('toCronExpression', () => {
|
||||
@@ -6,7 +7,7 @@ describe('Cron', () => {
|
||||
const expression = toCronExpression({
|
||||
mode: 'everyMinute',
|
||||
});
|
||||
expect(expression).toMatch(/^[1-6]?[0-9] \* \* \* \* \*$/);
|
||||
expect(expression).toMatch(/^[1-5]?[0-9] \* \* \* \* \*$/);
|
||||
});
|
||||
|
||||
test('should generate a valid cron for `everyHour` triggers', () => {
|
||||
@@ -14,7 +15,7 @@ describe('Cron', () => {
|
||||
mode: 'everyHour',
|
||||
minute: 11,
|
||||
});
|
||||
expect(expression).toMatch(/^[1-6]?[0-9] 11 \* \* \* \*$/);
|
||||
expect(expression).toMatch(/^[1-5]?[0-9] 11 \* \* \* \*$/);
|
||||
});
|
||||
|
||||
test('should generate a valid cron for `everyX[minutes]` triggers', () => {
|
||||
@@ -23,7 +24,7 @@ describe('Cron', () => {
|
||||
unit: 'minutes',
|
||||
value: 42,
|
||||
});
|
||||
expect(expression).toMatch(/^[1-6]?[0-9] \*\/42 \* \* \* \*$/);
|
||||
expect(expression).toMatch(/^[1-5]?[0-9] \*\/42 \* \* \* \*$/);
|
||||
});
|
||||
|
||||
test('should generate a valid cron for `everyX[hours]` triggers', () => {
|
||||
@@ -32,7 +33,7 @@ describe('Cron', () => {
|
||||
unit: 'hours',
|
||||
value: 3,
|
||||
});
|
||||
expect(expression).toMatch(/^[1-6]?[0-9] 0 \*\/3 \* \* \*$/);
|
||||
expect(expression).toMatch(/^[1-5]?[0-9] [1-5]?[0-9] \*\/3 \* \* \*$/);
|
||||
});
|
||||
|
||||
test('should generate a valid cron for `everyDay` triggers', () => {
|
||||
@@ -41,7 +42,7 @@ describe('Cron', () => {
|
||||
hour: 13,
|
||||
minute: 17,
|
||||
});
|
||||
expect(expression).toMatch(/^[1-6]?[0-9] 17 13 \* \* \*$/);
|
||||
expect(expression).toMatch(/^[1-5]?[0-9] 17 13 \* \* \*$/);
|
||||
});
|
||||
|
||||
test('should generate a valid cron for `everyWeek` triggers', () => {
|
||||
@@ -51,7 +52,7 @@ describe('Cron', () => {
|
||||
minute: 17,
|
||||
weekday: 4,
|
||||
});
|
||||
expect(expression).toMatch(/^[1-6]?[0-9] 17 13 \* \* 4$/);
|
||||
expect(expression).toMatch(/^[1-5]?[0-9] 17 13 \* \* 4$/);
|
||||
});
|
||||
|
||||
test('should generate a valid cron for `everyMonth` triggers', () => {
|
||||
@@ -61,13 +62,13 @@ describe('Cron', () => {
|
||||
minute: 17,
|
||||
dayOfMonth: 12,
|
||||
});
|
||||
expect(expression).toMatch(/^[1-6]?[0-9] 17 13 12 \* \*$/);
|
||||
expect(expression).toMatch(/^[1-5]?[0-9] 17 13 12 \* \*$/);
|
||||
});
|
||||
|
||||
test('should trim custom cron expressions', () => {
|
||||
const expression = toCronExpression({
|
||||
mode: 'custom',
|
||||
cronExpression: ' 0 9-17 * * * ',
|
||||
cronExpression: ' 0 9-17 * * * ' as CronExpression,
|
||||
});
|
||||
expect(expression).toEqual('0 9-17 * * *');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user