@nocobase/plugin-workflow 1.7.0-beta.9 → 1.8.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/602ab29d66b356c4.js +10 -0
- package/dist/client/77f05f24f6a5f421.js +10 -0
- package/dist/client/7af2da3defaae26f.js +10 -0
- package/dist/client/WorkflowCategoryTabs.d.ts +10 -0
- package/dist/client/WorkflowCollectionsProvider.d.ts +10 -0
- package/dist/client/WorkflowTasks.d.ts +12 -3
- package/dist/client/components/EmunerationField.d.ts +9 -0
- package/dist/client/e03d641492559086.js +10 -0
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.js +1 -1
- package/dist/client/locale/index.d.ts +2 -1
- package/dist/client/schemas/executions.d.ts +126 -125
- package/dist/client/triggers/schedule/RepeatField.d.ts +2 -1
- package/dist/common/collections/executions.d.ts +136 -0
- package/dist/common/collections/executions.js +125 -0
- package/dist/common/collections/flow_nodes.d.ts +65 -0
- package/dist/common/collections/flow_nodes.js +94 -0
- package/dist/common/collections/jobs.d.ts +37 -0
- package/dist/common/collections/jobs.js +74 -0
- package/dist/common/collections/userWorkflowTasks.d.ts +37 -0
- package/dist/common/collections/userWorkflowTasks.js +65 -0
- package/dist/common/collections/workflowCategories.d.ts +65 -0
- package/dist/common/collections/workflowCategories.js +68 -0
- package/dist/common/collections/workflowCategoryRelations.d.ts +21 -0
- package/dist/common/collections/workflowCategoryRelations.js +51 -0
- package/dist/common/collections/workflowStats.d.ts +37 -0
- package/dist/common/collections/workflowStats.js +59 -0
- package/dist/common/collections/workflowTasks.d.ts +10 -0
- package/dist/common/collections/workflowTasks.js +64 -0
- package/dist/common/collections/workflowVersionStats.d.ts +37 -0
- package/dist/common/collections/workflowVersionStats.js +59 -0
- package/dist/common/collections/workflows.d.ts +263 -0
- package/dist/common/collections/workflows.js +244 -0
- package/dist/common/constants.d.ts +9 -0
- package/dist/{server/actions/workflowTasks.js → common/constants.js} +6 -17
- package/dist/externalVersion.js +12 -11
- package/dist/locale/en-US.json +127 -15
- package/dist/locale/zh-CN.json +10 -1
- package/dist/node_modules/cron-parser/package.json +1 -1
- package/dist/node_modules/lru-cache/package.json +1 -1
- package/dist/node_modules/nodejs-snowflake/LICENSE +201 -0
- package/dist/node_modules/nodejs-snowflake/nodejs_snowflake.d.ts +62 -0
- package/dist/node_modules/nodejs-snowflake/nodejs_snowflake.js +1 -0
- package/dist/node_modules/nodejs-snowflake/nodejs_snowflake_bg.wasm +0 -0
- package/dist/node_modules/nodejs-snowflake/package.json +1 -0
- package/dist/server/Dispatcher.d.ts +11 -0
- package/dist/server/Dispatcher.js +35 -0
- package/dist/server/Plugin.d.ts +13 -2
- package/dist/server/Plugin.js +170 -107
- package/dist/server/Processor.d.ts +4 -11
- package/dist/server/Processor.js +50 -45
- package/dist/server/actions/index.js +2 -2
- package/dist/server/actions/nodes.js +7 -5
- package/dist/server/actions/{workflowTasks.d.ts → userWorkflowTasks.d.ts} +1 -1
- package/dist/server/actions/userWorkflowTasks.js +54 -0
- package/dist/server/actions/workflows.js +6 -3
- package/dist/server/collections/executions.js +12 -44
- package/dist/server/collections/flow_nodes.js +12 -57
- package/dist/server/collections/jobs.js +12 -36
- package/dist/server/collections/userWorkflowTasks.d.ts +11 -0
- package/dist/server/collections/userWorkflowTasks.js +43 -0
- package/dist/server/collections/workflowCategories.d.ts +11 -0
- package/dist/server/collections/workflowCategories.js +43 -0
- package/dist/server/collections/workflowCategoryRelations.d.ts +11 -0
- package/dist/server/collections/workflowCategoryRelations.js +43 -0
- package/dist/server/collections/workflowStats.d.ts +11 -0
- package/dist/server/collections/workflowStats.js +43 -0
- package/dist/server/collections/workflowTasks.d.ts +2 -1
- package/dist/server/collections/workflowTasks.js +12 -33
- package/dist/server/collections/workflowVersionStats.d.ts +11 -0
- package/dist/server/collections/workflowVersionStats.js +43 -0
- package/dist/server/collections/workflows.d.ts +2 -1
- package/dist/server/collections/workflows.js +12 -101
- package/dist/server/migrations/20250320223415-stats.d.ts +14 -0
- package/dist/server/migrations/20250320223415-stats.js +82 -0
- package/dist/server/migrations/20250409164913-remove-jobs-auto-increment.d.ts +14 -0
- package/dist/server/migrations/20250409164913-remove-jobs-auto-increment.js +57 -0
- package/dist/server/repositories/WorkflowRepository.js +3 -2
- package/dist/server/triggers/CollectionTrigger.js +3 -2
- package/dist/server/triggers/ScheduleTrigger/DateFieldScheduleTrigger.d.ts +5 -3
- package/dist/server/triggers/ScheduleTrigger/DateFieldScheduleTrigger.js +39 -36
- package/dist/server/triggers/ScheduleTrigger/StaticScheduleTrigger.d.ts +4 -2
- package/dist/server/triggers/ScheduleTrigger/StaticScheduleTrigger.js +26 -24
- package/dist/server/triggers/ScheduleTrigger/index.d.ts +2 -1
- package/dist/server/triggers/ScheduleTrigger/index.js +4 -8
- package/dist/server/triggers/index.d.ts +1 -1
- package/dist/server/types/Workflow.d.ts +0 -2
- package/dist/swagger/index.d.ts +0 -14
- package/dist/swagger/index.js +0 -14
- package/package.json +6 -4
- package/dist/client/739d458621edf81f.js +0 -10
- package/dist/client/8e96ce6ed324ce69.js +0 -10
- package/dist/client/c107ec5004b8644b.js +0 -10
- package/dist/client/c3f36ae11fcc489e.js +0 -10
- package/dist/client/nodes/output.d.ts +0 -31
package/dist/server/Plugin.d.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
|
+
import { Snowflake } from 'nodejs-snowflake';
|
|
9
10
|
import { Transactionable } from 'sequelize';
|
|
10
11
|
import { Plugin } from '@nocobase/server';
|
|
11
12
|
import { Registry } from '@nocobase/utils';
|
|
@@ -14,7 +15,7 @@ import Processor from './Processor';
|
|
|
14
15
|
import { CustomFunction } from './functions';
|
|
15
16
|
import Trigger from './triggers';
|
|
16
17
|
import { InstructionInterface } from './instructions';
|
|
17
|
-
import type { ExecutionModel, WorkflowModel
|
|
18
|
+
import type { ExecutionModel, WorkflowModel } from './types';
|
|
18
19
|
type ID = number | string;
|
|
19
20
|
export type EventOptions = {
|
|
20
21
|
eventKey?: string;
|
|
@@ -31,6 +32,7 @@ export default class PluginWorkflowServer extends Plugin {
|
|
|
31
32
|
triggers: Registry<Trigger>;
|
|
32
33
|
functions: Registry<CustomFunction>;
|
|
33
34
|
enabledCache: Map<number, WorkflowModel>;
|
|
35
|
+
snowflake: Snowflake;
|
|
34
36
|
private ready;
|
|
35
37
|
private executing;
|
|
36
38
|
private pending;
|
|
@@ -39,7 +41,13 @@ export default class PluginWorkflowServer extends Plugin {
|
|
|
39
41
|
private loggerCache;
|
|
40
42
|
private meter;
|
|
41
43
|
private checker;
|
|
44
|
+
private onQueueExecution;
|
|
42
45
|
private onBeforeSave;
|
|
46
|
+
private onAfterCreate;
|
|
47
|
+
private onAfterUpdate;
|
|
48
|
+
private onAfterDestroy;
|
|
49
|
+
private onAfterStart;
|
|
50
|
+
private onBeforeStop;
|
|
43
51
|
handleSyncMessage(message: any): Promise<void>;
|
|
44
52
|
/**
|
|
45
53
|
* @experimental
|
|
@@ -91,6 +99,9 @@ export default class PluginWorkflowServer extends Plugin {
|
|
|
91
99
|
/**
|
|
92
100
|
* @experimental
|
|
93
101
|
*/
|
|
94
|
-
|
|
102
|
+
updateTasksStats(userId: number, type: string, stats: {
|
|
103
|
+
pending: number;
|
|
104
|
+
all: number;
|
|
105
|
+
}, { transaction }: Transactionable): Promise<void>;
|
|
95
106
|
}
|
|
96
107
|
export {};
|
package/dist/server/Plugin.js
CHANGED
|
@@ -41,6 +41,7 @@ __export(Plugin_exports, {
|
|
|
41
41
|
module.exports = __toCommonJS(Plugin_exports);
|
|
42
42
|
var import_path = __toESM(require("path"));
|
|
43
43
|
var import_crypto = require("crypto");
|
|
44
|
+
var import_nodejs_snowflake = require("nodejs-snowflake");
|
|
44
45
|
var import_sequelize = require("sequelize");
|
|
45
46
|
var import_lru_cache = __toESM(require("lru-cache"));
|
|
46
47
|
var import_database = require("@nocobase/database");
|
|
@@ -60,12 +61,12 @@ var import_DestroyInstruction = __toESM(require("./instructions/DestroyInstructi
|
|
|
60
61
|
var import_QueryInstruction = __toESM(require("./instructions/QueryInstruction"));
|
|
61
62
|
var import_UpdateInstruction = __toESM(require("./instructions/UpdateInstruction"));
|
|
62
63
|
var import_WorkflowRepository = __toESM(require("./repositories/WorkflowRepository"));
|
|
63
|
-
var import_WorkflowTasksRepository = __toESM(require("./repositories/WorkflowTasksRepository"));
|
|
64
64
|
class PluginWorkflowServer extends import_server.Plugin {
|
|
65
65
|
instructions = new import_utils.Registry();
|
|
66
66
|
triggers = new import_utils.Registry();
|
|
67
67
|
functions = new import_utils.Registry();
|
|
68
68
|
enabledCache = /* @__PURE__ */ new Map();
|
|
69
|
+
snowflake;
|
|
69
70
|
ready = false;
|
|
70
71
|
executing = null;
|
|
71
72
|
pending = [];
|
|
@@ -74,8 +75,28 @@ class PluginWorkflowServer extends import_server.Plugin {
|
|
|
74
75
|
loggerCache;
|
|
75
76
|
meter = null;
|
|
76
77
|
checker = null;
|
|
77
|
-
|
|
78
|
+
onQueueExecution = async (event) => {
|
|
79
|
+
const ExecutionRepo = this.db.getRepository("executions");
|
|
80
|
+
const execution = await ExecutionRepo.findOne({
|
|
81
|
+
filterByTk: event.executionId
|
|
82
|
+
});
|
|
83
|
+
if (!execution || execution.status !== import_constants.EXECUTION_STATUS.QUEUEING) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
this.getLogger(execution.workflowId).info(
|
|
87
|
+
`execution (${execution.id}) received from queue, adding to pending list`
|
|
88
|
+
);
|
|
89
|
+
this.pending.push([execution]);
|
|
90
|
+
this.dispatch();
|
|
91
|
+
};
|
|
92
|
+
onBeforeSave = async (instance, { transaction, cycling }) => {
|
|
93
|
+
if (cycling) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
78
96
|
const Model = instance.constructor;
|
|
97
|
+
if (!instance.key) {
|
|
98
|
+
instance.set("key", (0, import_utils.uid)());
|
|
99
|
+
}
|
|
79
100
|
if (instance.enabled) {
|
|
80
101
|
instance.set("current", true);
|
|
81
102
|
}
|
|
@@ -91,18 +112,95 @@ class PluginWorkflowServer extends import_server.Plugin {
|
|
|
91
112
|
});
|
|
92
113
|
if (!previous) {
|
|
93
114
|
instance.set("current", true);
|
|
94
|
-
}
|
|
95
|
-
if (instance.current && previous) {
|
|
115
|
+
} else if (instance.current) {
|
|
96
116
|
await previous.update(
|
|
97
117
|
{ enabled: false, current: null },
|
|
98
118
|
{
|
|
99
119
|
transaction,
|
|
100
|
-
|
|
120
|
+
cycling: true
|
|
101
121
|
}
|
|
102
122
|
);
|
|
103
123
|
this.toggle(previous, false, { transaction });
|
|
104
124
|
}
|
|
105
125
|
};
|
|
126
|
+
onAfterCreate = async (model, { transaction }) => {
|
|
127
|
+
const WorkflowStatsModel = this.db.getModel("workflowStats");
|
|
128
|
+
let stats = await WorkflowStatsModel.findOne({
|
|
129
|
+
where: { key: model.key },
|
|
130
|
+
transaction
|
|
131
|
+
});
|
|
132
|
+
if (!stats) {
|
|
133
|
+
stats = await model.createStats({ executed: 0 }, { transaction });
|
|
134
|
+
}
|
|
135
|
+
model.stats = stats;
|
|
136
|
+
model.versionStats = await model.createVersionStats({ id: model.id }, { transaction });
|
|
137
|
+
if (model.enabled) {
|
|
138
|
+
this.toggle(model, true, { transaction });
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
onAfterUpdate = async (model, { transaction }) => {
|
|
142
|
+
model.stats = await model.getStats({ transaction });
|
|
143
|
+
model.versionStats = await model.getVersionStats({ transaction });
|
|
144
|
+
this.toggle(model, model.enabled, { transaction });
|
|
145
|
+
};
|
|
146
|
+
onAfterDestroy = async (model, { transaction }) => {
|
|
147
|
+
this.toggle(model, false, { transaction });
|
|
148
|
+
const TaskRepo = this.db.getRepository("workflowTasks");
|
|
149
|
+
await TaskRepo.destroy({
|
|
150
|
+
filter: {
|
|
151
|
+
workflowId: model.id
|
|
152
|
+
},
|
|
153
|
+
transaction
|
|
154
|
+
});
|
|
155
|
+
};
|
|
156
|
+
// [Life Cycle]:
|
|
157
|
+
// * load all workflows in db
|
|
158
|
+
// * add all hooks for enabled workflows
|
|
159
|
+
// * add hooks for create/update[enabled]/delete workflow to add/remove specific hooks
|
|
160
|
+
onAfterStart = async () => {
|
|
161
|
+
this.ready = true;
|
|
162
|
+
const collection = this.db.getCollection("workflows");
|
|
163
|
+
const workflows = await collection.repository.find({
|
|
164
|
+
filter: { enabled: true },
|
|
165
|
+
appends: ["stats", "versionStats"]
|
|
166
|
+
});
|
|
167
|
+
for (const workflow of workflows) {
|
|
168
|
+
if (!workflow.stats) {
|
|
169
|
+
workflow.stats = await workflow.createStats({ executed: 0 });
|
|
170
|
+
}
|
|
171
|
+
if (!workflow.versionStats) {
|
|
172
|
+
workflow.versionStats = await workflow.createVersionStats({ executed: 0 });
|
|
173
|
+
}
|
|
174
|
+
this.toggle(workflow, true, { silent: true });
|
|
175
|
+
}
|
|
176
|
+
this.checker = setInterval(() => {
|
|
177
|
+
this.getLogger("dispatcher").info(`(cycling) check for queueing executions`);
|
|
178
|
+
this.dispatch();
|
|
179
|
+
}, 3e5);
|
|
180
|
+
this.app.on("workflow:dispatch", () => {
|
|
181
|
+
this.app.logger.info("workflow:dispatch");
|
|
182
|
+
this.dispatch();
|
|
183
|
+
});
|
|
184
|
+
this.getLogger("dispatcher").info("(starting) check for queueing executions");
|
|
185
|
+
this.dispatch();
|
|
186
|
+
this.ready = true;
|
|
187
|
+
};
|
|
188
|
+
onBeforeStop = async () => {
|
|
189
|
+
this.app.logger.info(`stopping workflow plugin before app (${this.app.name}) shutdown...`);
|
|
190
|
+
for (const workflow of this.enabledCache.values()) {
|
|
191
|
+
this.toggle(workflow, false, { silent: true });
|
|
192
|
+
}
|
|
193
|
+
this.ready = false;
|
|
194
|
+
if (this.events.length) {
|
|
195
|
+
await this.prepare();
|
|
196
|
+
}
|
|
197
|
+
if (this.executing) {
|
|
198
|
+
await this.executing;
|
|
199
|
+
}
|
|
200
|
+
if (this.checker) {
|
|
201
|
+
clearInterval(this.checker);
|
|
202
|
+
}
|
|
203
|
+
};
|
|
106
204
|
async handleSyncMessage(message) {
|
|
107
205
|
if (message.type === "statusChange") {
|
|
108
206
|
if (message.enabled) {
|
|
@@ -193,8 +291,18 @@ class PluginWorkflowServer extends import_server.Plugin {
|
|
|
193
291
|
}
|
|
194
292
|
async beforeLoad() {
|
|
195
293
|
this.db.registerRepositories({
|
|
196
|
-
WorkflowRepository: import_WorkflowRepository.default
|
|
197
|
-
|
|
294
|
+
WorkflowRepository: import_WorkflowRepository.default
|
|
295
|
+
});
|
|
296
|
+
const PluginRepo = this.db.getRepository("applicationPlugins");
|
|
297
|
+
const pluginRecord = await PluginRepo.findOne({
|
|
298
|
+
filter: { name: this.name }
|
|
299
|
+
});
|
|
300
|
+
this.snowflake = new import_nodejs_snowflake.Snowflake({
|
|
301
|
+
custom_epoch: pluginRecord == null ? void 0 : pluginRecord.createdAt.getTime()
|
|
302
|
+
});
|
|
303
|
+
this.app.eventQueue.subscribe(`${this.name}.pendingExecution`, {
|
|
304
|
+
idle: () => !this.executing && !this.pending.length && !this.events.length,
|
|
305
|
+
process: this.onQueueExecution
|
|
198
306
|
});
|
|
199
307
|
}
|
|
200
308
|
/**
|
|
@@ -230,77 +338,22 @@ class PluginWorkflowServer extends import_server.Plugin {
|
|
|
230
338
|
"flow_nodes:update",
|
|
231
339
|
"flow_nodes:destroy",
|
|
232
340
|
"flow_nodes:test",
|
|
233
|
-
"jobs:get"
|
|
341
|
+
"jobs:get",
|
|
342
|
+
"workflowCategories:*"
|
|
234
343
|
]
|
|
235
344
|
});
|
|
236
345
|
this.app.acl.registerSnippet({
|
|
237
346
|
name: "ui.workflows",
|
|
238
347
|
actions: ["workflows:list"]
|
|
239
348
|
});
|
|
240
|
-
this.app.acl.allow("
|
|
349
|
+
this.app.acl.allow("userWorkflowTasks", "listMine", "loggedIn");
|
|
241
350
|
this.app.acl.allow("*", ["trigger"], "loggedIn");
|
|
242
|
-
this.db.addMigrations({
|
|
243
|
-
namespace: this.name,
|
|
244
|
-
directory: import_path.default.resolve(__dirname, "migrations"),
|
|
245
|
-
context: {
|
|
246
|
-
plugin: this
|
|
247
|
-
}
|
|
248
|
-
});
|
|
249
351
|
db.on("workflows.beforeSave", this.onBeforeSave);
|
|
250
|
-
db.on("workflows.afterCreate",
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
db.on(
|
|
256
|
-
"workflows.afterUpdate",
|
|
257
|
-
(model, { transaction }) => this.toggle(model, model.enabled, { transaction })
|
|
258
|
-
);
|
|
259
|
-
db.on("workflows.afterDestroy", async (model, { transaction }) => {
|
|
260
|
-
this.toggle(model, false, { transaction });
|
|
261
|
-
const TaskRepo = this.db.getRepository("workflowTasks");
|
|
262
|
-
await TaskRepo.destroy({
|
|
263
|
-
filter: {
|
|
264
|
-
workflowId: model.id
|
|
265
|
-
},
|
|
266
|
-
transaction
|
|
267
|
-
});
|
|
268
|
-
});
|
|
269
|
-
this.app.on("afterStart", async () => {
|
|
270
|
-
this.ready = true;
|
|
271
|
-
const collection = db.getCollection("workflows");
|
|
272
|
-
const workflows = await collection.repository.find({
|
|
273
|
-
filter: { enabled: true }
|
|
274
|
-
});
|
|
275
|
-
workflows.forEach((workflow) => {
|
|
276
|
-
this.toggle(workflow, true, { silent: true });
|
|
277
|
-
});
|
|
278
|
-
this.checker = setInterval(() => {
|
|
279
|
-
this.getLogger("dispatcher").info(`(cycling) check for queueing executions`);
|
|
280
|
-
this.dispatch();
|
|
281
|
-
}, 3e5);
|
|
282
|
-
this.app.on("workflow:dispatch", () => {
|
|
283
|
-
this.app.logger.info("workflow:dispatch");
|
|
284
|
-
this.dispatch();
|
|
285
|
-
});
|
|
286
|
-
this.getLogger("dispatcher").info("(starting) check for queueing executions");
|
|
287
|
-
this.dispatch();
|
|
288
|
-
});
|
|
289
|
-
this.app.on("beforeStop", async () => {
|
|
290
|
-
for (const workflow of this.enabledCache.values()) {
|
|
291
|
-
this.toggle(workflow, false, { silent: true });
|
|
292
|
-
}
|
|
293
|
-
this.ready = false;
|
|
294
|
-
if (this.events.length) {
|
|
295
|
-
await this.prepare();
|
|
296
|
-
}
|
|
297
|
-
if (this.executing) {
|
|
298
|
-
await this.executing;
|
|
299
|
-
}
|
|
300
|
-
if (this.checker) {
|
|
301
|
-
clearInterval(this.checker);
|
|
302
|
-
}
|
|
303
|
-
});
|
|
352
|
+
db.on("workflows.afterCreate", this.onAfterCreate);
|
|
353
|
+
db.on("workflows.afterUpdate", this.onAfterUpdate);
|
|
354
|
+
db.on("workflows.afterDestroy", this.onAfterDestroy);
|
|
355
|
+
this.app.on("afterStart", this.onAfterStart);
|
|
356
|
+
this.app.on("beforeStop", this.onBeforeStop);
|
|
304
357
|
}
|
|
305
358
|
toggle(workflow, enable, { silent, transaction } = {}) {
|
|
306
359
|
const type = workflow.get("type");
|
|
@@ -314,11 +367,14 @@ class PluginWorkflowServer extends import_server.Plugin {
|
|
|
314
367
|
const prev = workflow.previous();
|
|
315
368
|
if (prev.config) {
|
|
316
369
|
trigger.off({ ...workflow.get(), ...prev });
|
|
370
|
+
this.getLogger(workflow.id).info(`toggle OFF workflow ${workflow.id} based on configuration before updated`);
|
|
317
371
|
}
|
|
318
372
|
trigger.on(workflow);
|
|
373
|
+
this.getLogger(workflow.id).info(`toggle ON workflow ${workflow.id}`);
|
|
319
374
|
this.enabledCache.set(workflow.id, workflow);
|
|
320
375
|
} else {
|
|
321
376
|
trigger.off(workflow);
|
|
377
|
+
this.getLogger(workflow.id).info(`toggle OFF workflow ${workflow.id}`);
|
|
322
378
|
this.enabledCache.delete(workflow.id);
|
|
323
379
|
}
|
|
324
380
|
if (!silent) {
|
|
@@ -470,21 +526,20 @@ class PluginWorkflowServer extends import_server.Plugin {
|
|
|
470
526
|
throw err;
|
|
471
527
|
}
|
|
472
528
|
this.getLogger(workflow.id).info(`execution of workflow ${workflow.id} created as ${execution.id}`);
|
|
473
|
-
|
|
529
|
+
if (!workflow.stats) {
|
|
530
|
+
workflow.stats = await workflow.getStats({ transaction });
|
|
531
|
+
}
|
|
532
|
+
await workflow.stats.increment("executed", { transaction });
|
|
474
533
|
if (this.db.options.dialect !== "postgres") {
|
|
475
|
-
await workflow.reload({ transaction });
|
|
534
|
+
await workflow.stats.reload({ transaction });
|
|
535
|
+
}
|
|
536
|
+
if (!workflow.versionStats) {
|
|
537
|
+
workflow.versionStats = await workflow.getVersionStats({ transaction });
|
|
538
|
+
}
|
|
539
|
+
await workflow.versionStats.increment("executed", { transaction });
|
|
540
|
+
if (this.db.options.dialect !== "postgres") {
|
|
541
|
+
await workflow.versionStats.reload({ transaction });
|
|
476
542
|
}
|
|
477
|
-
await workflow.constructor.update(
|
|
478
|
-
{
|
|
479
|
-
allExecuted: workflow.allExecuted
|
|
480
|
-
},
|
|
481
|
-
{
|
|
482
|
-
where: {
|
|
483
|
-
key: workflow.key
|
|
484
|
-
},
|
|
485
|
-
transaction
|
|
486
|
-
}
|
|
487
|
-
);
|
|
488
543
|
if (!sameTransaction) {
|
|
489
544
|
await transaction.commit();
|
|
490
545
|
}
|
|
@@ -505,8 +560,14 @@ class PluginWorkflowServer extends import_server.Plugin {
|
|
|
505
560
|
logger.info(`preparing execution for event`);
|
|
506
561
|
try {
|
|
507
562
|
const execution = await this.createExecution(...event);
|
|
508
|
-
if ((execution == null ? void 0 : execution.status) === import_constants.EXECUTION_STATUS.QUEUEING
|
|
509
|
-
this.pending.
|
|
563
|
+
if ((execution == null ? void 0 : execution.status) === import_constants.EXECUTION_STATUS.QUEUEING) {
|
|
564
|
+
if (!this.executing && !this.pending.length) {
|
|
565
|
+
logger.info(`local pending list is empty, adding execution (${execution.id}) to pending list`);
|
|
566
|
+
this.pending.push([execution]);
|
|
567
|
+
} else {
|
|
568
|
+
logger.info(`local pending list is not empty, sending execution (${execution.id}) to queue`);
|
|
569
|
+
this.app.eventQueue.publish(`${this.name}.pendingExecution`, { executionId: execution.id });
|
|
570
|
+
}
|
|
510
571
|
}
|
|
511
572
|
} catch (error) {
|
|
512
573
|
logger.error(`failed to create execution:`, { error });
|
|
@@ -638,36 +699,38 @@ class PluginWorkflowServer extends import_server.Plugin {
|
|
|
638
699
|
/**
|
|
639
700
|
* @experimental
|
|
640
701
|
*/
|
|
641
|
-
async
|
|
702
|
+
async updateTasksStats(userId, type, stats = { pending: 0, all: 0 }, { transaction }) {
|
|
642
703
|
const { db } = this.app;
|
|
643
|
-
const repository = db.getRepository("
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
704
|
+
const repository = db.getRepository("userWorkflowTasks");
|
|
705
|
+
let record = await repository.findOne({
|
|
706
|
+
filter: {
|
|
707
|
+
userId,
|
|
708
|
+
type
|
|
709
|
+
},
|
|
710
|
+
transaction
|
|
711
|
+
});
|
|
712
|
+
if (record) {
|
|
713
|
+
await record.update(
|
|
714
|
+
{
|
|
715
|
+
stats
|
|
649
716
|
},
|
|
650
|
-
transaction
|
|
651
|
-
|
|
717
|
+
{ transaction }
|
|
718
|
+
);
|
|
652
719
|
} else {
|
|
653
|
-
await repository.
|
|
654
|
-
|
|
655
|
-
|
|
720
|
+
record = await repository.create({
|
|
721
|
+
values: {
|
|
722
|
+
userId,
|
|
723
|
+
type,
|
|
724
|
+
stats
|
|
725
|
+
},
|
|
656
726
|
transaction
|
|
657
727
|
});
|
|
658
728
|
}
|
|
659
|
-
if (
|
|
660
|
-
const counts = await repository.countAll({
|
|
661
|
-
where: {
|
|
662
|
-
userId: task.userId,
|
|
663
|
-
workflowId: { [import_database.Op.ne]: null }
|
|
664
|
-
},
|
|
665
|
-
transaction
|
|
666
|
-
}) || [];
|
|
729
|
+
if (userId) {
|
|
667
730
|
this.app.emit("ws:sendToTag", {
|
|
668
731
|
tagKey: "userId",
|
|
669
|
-
tagValue: `${
|
|
670
|
-
message: { type: "workflow:tasks:updated", payload:
|
|
732
|
+
tagValue: `${userId}`,
|
|
733
|
+
message: { type: "workflow:tasks:updated", payload: record.get() }
|
|
671
734
|
});
|
|
672
735
|
}
|
|
673
736
|
}
|
|
@@ -44,16 +44,9 @@ export default class Processor {
|
|
|
44
44
|
* @experimental
|
|
45
45
|
*/
|
|
46
46
|
nodesMap: Map<number, FlowNodeModel>;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
jobsMap: Map<number, JobModel>;
|
|
51
|
-
/**
|
|
52
|
-
* @experimental
|
|
53
|
-
*/
|
|
54
|
-
jobsMapByNodeKey: {
|
|
55
|
-
[key: string]: any;
|
|
56
|
-
};
|
|
47
|
+
private jobsMapByNodeKey;
|
|
48
|
+
private jobResultsMapByNodeKey;
|
|
49
|
+
private jobsToSave;
|
|
57
50
|
/**
|
|
58
51
|
* @experimental
|
|
59
52
|
*/
|
|
@@ -72,7 +65,7 @@ export default class Processor {
|
|
|
72
65
|
/**
|
|
73
66
|
* @experimental
|
|
74
67
|
*/
|
|
75
|
-
saveJob(payload: JobModel | Record<string, any>):
|
|
68
|
+
saveJob(payload: JobModel | Record<string, any>): JobModel;
|
|
76
69
|
/**
|
|
77
70
|
* @experimental
|
|
78
71
|
*/
|
package/dist/server/Processor.js
CHANGED
|
@@ -78,14 +78,9 @@ class Processor {
|
|
|
78
78
|
* @experimental
|
|
79
79
|
*/
|
|
80
80
|
nodesMap = /* @__PURE__ */ new Map();
|
|
81
|
-
/**
|
|
82
|
-
* @experimental
|
|
83
|
-
*/
|
|
84
|
-
jobsMap = /* @__PURE__ */ new Map();
|
|
85
|
-
/**
|
|
86
|
-
* @experimental
|
|
87
|
-
*/
|
|
88
81
|
jobsMapByNodeKey = {};
|
|
82
|
+
jobResultsMapByNodeKey = {};
|
|
83
|
+
jobsToSave = /* @__PURE__ */ new Map();
|
|
89
84
|
/**
|
|
90
85
|
* @experimental
|
|
91
86
|
*/
|
|
@@ -107,9 +102,9 @@ class Processor {
|
|
|
107
102
|
}
|
|
108
103
|
makeJobs(jobs) {
|
|
109
104
|
jobs.forEach((job) => {
|
|
110
|
-
this.jobsMap.set(job.id, job);
|
|
111
105
|
const node = this.nodesMap.get(job.nodeId);
|
|
112
|
-
this.jobsMapByNodeKey[node.key] = job
|
|
106
|
+
this.jobsMapByNodeKey[node.key] = job;
|
|
107
|
+
this.jobResultsMapByNodeKey[node.key] = job.result;
|
|
113
108
|
});
|
|
114
109
|
}
|
|
115
110
|
async prepare() {
|
|
@@ -123,11 +118,13 @@ class Processor {
|
|
|
123
118
|
execution.workflow = plugin.enabledCache.get(execution.workflowId) || await execution.getWorkflow({ transaction });
|
|
124
119
|
}
|
|
125
120
|
const nodes = await execution.workflow.getNodes({ transaction });
|
|
121
|
+
execution.workflow.nodes = nodes;
|
|
126
122
|
this.makeNodes(nodes);
|
|
127
123
|
const jobs = await execution.getJobs({
|
|
128
124
|
order: [["id", "ASC"]],
|
|
129
125
|
transaction
|
|
130
126
|
});
|
|
127
|
+
execution.jobs = jobs;
|
|
131
128
|
this.makeJobs(jobs);
|
|
132
129
|
}
|
|
133
130
|
async start() {
|
|
@@ -179,11 +176,10 @@ class Processor {
|
|
|
179
176
|
}
|
|
180
177
|
}
|
|
181
178
|
if (!(job instanceof import_database.Model)) {
|
|
182
|
-
job.upstreamId = prevJob instanceof import_database.Model ? prevJob.get("id") : null;
|
|
183
179
|
job.nodeId = node.id;
|
|
184
180
|
job.nodeKey = node.key;
|
|
185
181
|
}
|
|
186
|
-
const savedJob =
|
|
182
|
+
const savedJob = this.saveJob(job);
|
|
187
183
|
this.logger.info(
|
|
188
184
|
`execution (${this.execution.id}) run instruction [${node.type}] for node (${node.id}) finished as status: ${savedJob.status}`
|
|
189
185
|
);
|
|
@@ -230,6 +226,30 @@ class Processor {
|
|
|
230
226
|
return this.exec(instruction.resume.bind(instruction), node, job);
|
|
231
227
|
}
|
|
232
228
|
async exit(s) {
|
|
229
|
+
if (this.jobsToSave.size) {
|
|
230
|
+
const newJobs = [];
|
|
231
|
+
for (const job of this.jobsToSave.values()) {
|
|
232
|
+
if (job.isNewRecord) {
|
|
233
|
+
newJobs.push(job);
|
|
234
|
+
} else {
|
|
235
|
+
await job.save({ transaction: this.mainTransaction });
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
if (newJobs.length) {
|
|
239
|
+
const JobsModel = this.options.plugin.db.getModel("jobs");
|
|
240
|
+
await JobsModel.bulkCreate(
|
|
241
|
+
newJobs.map((job) => job.toJSON()),
|
|
242
|
+
{
|
|
243
|
+
transaction: this.mainTransaction,
|
|
244
|
+
returning: false
|
|
245
|
+
}
|
|
246
|
+
);
|
|
247
|
+
for (const job of newJobs) {
|
|
248
|
+
job.isNewRecord = false;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
this.jobsToSave.clear();
|
|
252
|
+
}
|
|
233
253
|
if (typeof s === "number") {
|
|
234
254
|
const status = this.constructor.StatusMap[s] ?? Math.sign(s);
|
|
235
255
|
await this.execution.update({ status }, { transaction: this.mainTransaction });
|
|
@@ -240,32 +260,29 @@ class Processor {
|
|
|
240
260
|
this.logger.info(`execution (${this.execution.id}) exiting with status ${this.execution.status}`);
|
|
241
261
|
return null;
|
|
242
262
|
}
|
|
243
|
-
// TODO(optimize)
|
|
244
263
|
/**
|
|
245
264
|
* @experimental
|
|
246
265
|
*/
|
|
247
|
-
|
|
266
|
+
saveJob(payload) {
|
|
248
267
|
const { database } = this.execution.constructor;
|
|
249
|
-
const { mainTransaction: transaction } = this;
|
|
250
268
|
const { model } = database.getCollection("jobs");
|
|
251
269
|
let job;
|
|
252
270
|
if (payload instanceof model) {
|
|
253
|
-
job =
|
|
254
|
-
|
|
255
|
-
job = await model.findByPk(payload.id, { transaction });
|
|
256
|
-
await job.update(payload, { transaction });
|
|
271
|
+
job = payload;
|
|
272
|
+
job.set("updatedAt", /* @__PURE__ */ new Date());
|
|
257
273
|
} else {
|
|
258
|
-
job =
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
);
|
|
274
|
+
job = model.build({
|
|
275
|
+
...payload,
|
|
276
|
+
id: this.options.plugin.snowflake.getUniqueID().toString(),
|
|
277
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
278
|
+
updatedAt: /* @__PURE__ */ new Date(),
|
|
279
|
+
executionId: this.execution.id
|
|
280
|
+
});
|
|
265
281
|
}
|
|
266
|
-
this.
|
|
282
|
+
this.jobsToSave.set(job.id, job);
|
|
267
283
|
this.lastSavedJob = job;
|
|
268
|
-
this.jobsMapByNodeKey[job.nodeKey] = job
|
|
284
|
+
this.jobsMapByNodeKey[job.nodeKey] = job;
|
|
285
|
+
this.jobResultsMapByNodeKey[job.nodeKey] = job.result;
|
|
269
286
|
return job;
|
|
270
287
|
}
|
|
271
288
|
/**
|
|
@@ -319,31 +336,19 @@ class Processor {
|
|
|
319
336
|
* @experimental
|
|
320
337
|
*/
|
|
321
338
|
findBranchParentJob(job, node) {
|
|
322
|
-
|
|
323
|
-
if (j.nodeId === node.id) {
|
|
324
|
-
return j;
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
return null;
|
|
339
|
+
return this.jobsMapByNodeKey[node.key];
|
|
328
340
|
}
|
|
329
341
|
/**
|
|
330
342
|
* @experimental
|
|
331
343
|
*/
|
|
332
344
|
findBranchLastJob(node, job) {
|
|
333
|
-
const allJobs =
|
|
345
|
+
const allJobs = Object.values(this.jobsMapByNodeKey);
|
|
334
346
|
const branchJobs = [];
|
|
335
347
|
for (let n = this.findBranchEndNode(node); n && n !== node.upstream; n = n.upstream) {
|
|
336
348
|
branchJobs.push(...allJobs.filter((item) => item.nodeId === n.id));
|
|
337
349
|
}
|
|
338
|
-
branchJobs.sort((a, b) => a.
|
|
339
|
-
|
|
340
|
-
for (let j = branchJobs[i]; j && j.id !== job.id; j = this.jobsMap.get(j.upstreamId)) {
|
|
341
|
-
if (j.upstreamId === job.id) {
|
|
342
|
-
return branchJobs[i];
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
return null;
|
|
350
|
+
branchJobs.sort((a, b) => a.updatedAt.getTime() - b.updatedAt.getTime());
|
|
351
|
+
return branchJobs[branchJobs.length - 1] || null;
|
|
347
352
|
}
|
|
348
353
|
/**
|
|
349
354
|
* @experimental
|
|
@@ -362,12 +367,12 @@ class Processor {
|
|
|
362
367
|
for (let n = includeSelfScope ? node : this.findBranchParentNode(node); n; n = this.findBranchParentNode(n)) {
|
|
363
368
|
const instruction = this.options.plugin.instructions.get(n.type);
|
|
364
369
|
if (typeof (instruction == null ? void 0 : instruction.getScope) === "function") {
|
|
365
|
-
$scopes[n.id] = $scopes[n.key] = instruction.getScope(n, this.
|
|
370
|
+
$scopes[n.id] = $scopes[n.key] = instruction.getScope(n, this.jobResultsMapByNodeKey[n.key], this);
|
|
366
371
|
}
|
|
367
372
|
}
|
|
368
373
|
return {
|
|
369
374
|
$context: this.execution.context,
|
|
370
|
-
$jobsMapByNodeKey: this.
|
|
375
|
+
$jobsMapByNodeKey: this.jobResultsMapByNodeKey,
|
|
371
376
|
$system: systemFns,
|
|
372
377
|
$scopes,
|
|
373
378
|
$env: this.options.plugin.app.environment.getVariables()
|
|
@@ -42,7 +42,7 @@ module.exports = __toCommonJS(actions_exports);
|
|
|
42
42
|
var workflows = __toESM(require("./workflows"));
|
|
43
43
|
var nodes = __toESM(require("./nodes"));
|
|
44
44
|
var executions = __toESM(require("./executions"));
|
|
45
|
-
var
|
|
45
|
+
var userWorkflowTasks = __toESM(require("./userWorkflowTasks"));
|
|
46
46
|
function make(name, mod) {
|
|
47
47
|
return Object.keys(mod).reduce(
|
|
48
48
|
(result, key) => ({
|
|
@@ -64,6 +64,6 @@ function actions_default({ app }) {
|
|
|
64
64
|
test: nodes.test
|
|
65
65
|
}),
|
|
66
66
|
...make("executions", executions),
|
|
67
|
-
...make("
|
|
67
|
+
...make("userWorkflowTasks", userWorkflowTasks)
|
|
68
68
|
});
|
|
69
69
|
}
|