UNPKG

@nocobase/plugin-workflow

Version:

A powerful BPM tool that provides foundational support for business automation, with the capability to extend unlimited triggers and nodes.

158 lines (156 loc) • 5.85 kB
/** * This file is part of the NocoBase (R) project. * Copyright (c) 2020-2024 NocoBase Co., Ltd. * Authors: NocoBase Team. * * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License. * For more information, please refer to: https://www.nocobase.com/agreement. */ var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var StaticScheduleTrigger_exports = {}; __export(StaticScheduleTrigger_exports, { default: () => StaticScheduleTrigger }); module.exports = __toCommonJS(StaticScheduleTrigger_exports); var import_cron_parser = __toESM(require("cron-parser")); var import_utils = require("./utils"); const MAX_SAFE_INTERVAL = 2147483647; class StaticScheduleTrigger { constructor(workflow) { this.workflow = workflow; workflow.app.on("afterStart", this.onAfterStart); workflow.app.on("beforeStop", this.onBeforeStop); } timers = /* @__PURE__ */ new Map(); onAfterStart = () => { const workflows = Array.from(this.workflow.enabledCache.values()).filter( (item) => item.type === "schedule" && item.config.mode === import_utils.SCHEDULE_MODE.STATIC ); workflows.forEach((workflow) => { this.inspect(workflow); }); }; onBeforeStop = () => { for (const timer of this.timers.values()) { clearInterval(timer); } }; inspect(workflow) { const now = /* @__PURE__ */ new Date(); const nextTime = this.getNextTime(workflow, now); if (nextTime) { this.workflow.getLogger(workflow.id).info(`caching scheduled workflow will run at: ${new Date(nextTime).toISOString()}`); } else { this.workflow.getLogger(workflow.id).info("workflow will not be scheduled"); } this.schedule(workflow, nextTime, nextTime >= now.getTime()); } getNextTime({ config, stats }, currentDate, nextSecond = false) { if (config.limit && stats.executed >= config.limit) { return null; } if (!config.startsOn) { return null; } currentDate.setMilliseconds(nextSecond ? 1e3 : 0); const timestamp = currentDate.getTime(); const startTime = (0, import_utils.parseDateWithoutMs)(config.startsOn); if (startTime > timestamp) { return startTime; } if (config.repeat) { const endTime = config.endsOn ? (0, import_utils.parseDateWithoutMs)(config.endsOn) : null; if (endTime && endTime < timestamp) { return null; } if (typeof config.repeat === "string") { const interval = import_cron_parser.default.parseExpression(config.repeat, { currentDate }); const next = interval.next(); return next.getTime(); } else if (typeof config.repeat === "number") { const next = timestamp + config.repeat - (timestamp - startTime) % config.repeat; return next; } else { return null; } } else { if (startTime < timestamp) { return null; } return timestamp; } } schedule(workflow, nextTime, toggle = true) { if (toggle) { const key = `${workflow.id}@${nextTime}`; if (!this.timers.has(key)) { const interval = Math.max(nextTime - Date.now(), 0); if (interval > MAX_SAFE_INTERVAL) { this.timers.set( key, setTimeout(() => { this.timers.delete(key); this.schedule(workflow, nextTime); }, MAX_SAFE_INTERVAL) ); } else { this.timers.set(key, setTimeout(this.trigger.bind(this, workflow, nextTime), interval)); } } } else { for (const [key, timer] of this.timers.entries()) { if (key.startsWith(`${workflow.id}@`)) { clearTimeout(timer); this.timers.delete(key); } } } } async trigger(workflow, time) { const eventKey = `${workflow.id}@${time}`; this.timers.delete(eventKey); this.workflow.trigger(workflow, { date: new Date(time) }, { eventKey }); if (!workflow.config.repeat || workflow.config.limit && workflow.stats.executed >= workflow.config.limit - 1) { return; } const nextTime = this.getNextTime(workflow, /* @__PURE__ */ new Date(), true); if (nextTime) { this.schedule(workflow, nextTime); } } on(workflow) { this.inspect(workflow); } off(workflow) { this.schedule(workflow, null, false); } execute(workflow, values, options) { return this.workflow.trigger(workflow, { ...values, date: (values == null ? void 0 : values.date) ?? /* @__PURE__ */ new Date() }, options); } }