@nocobase/plugin-workflow 2.1.0-beta.9 → 2.2.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/214.7e602cfe7a8251b8.js +10 -0
- package/dist/client/618.19af7f84261c815d.js +10 -0
- package/dist/client/67.452743ce8ec30617.js +10 -0
- package/dist/client/964.ffbf5b47ed12bbdc.js +10 -0
- package/dist/client/Branch.d.ts +7 -3
- package/dist/client/BranchContext.d.ts +18 -0
- package/dist/client/components/TimeoutInput.d.ts +11 -0
- package/dist/client/constants.d.ts +13 -0
- package/dist/client/flows/triggerWorkflows.d.ts +14 -1
- package/dist/client/hooks/{useWorkflowFilterActionProps.d.ts → useResourceFilterActionProps.d.ts} +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/nodes/create.d.ts +10 -0
- package/dist/client/nodes/destroy.d.ts +10 -0
- package/dist/client/nodes/index.d.ts +5 -0
- package/dist/client/nodes/query.d.ts +18 -2
- package/dist/client/nodes/update.d.ts +10 -0
- package/dist/client/schemas/collection.d.ts +8 -2
- package/dist/client/schemas/executions.d.ts +63 -2
- package/dist/client/triggers/collection.d.ts +14 -1
- package/dist/client/triggers/index.d.ts +4 -0
- package/dist/client/triggers/schedule/constants.d.ts +4 -0
- package/dist/client/triggers/schedule/index.d.ts +15 -0
- package/dist/client/utils.d.ts +17 -0
- package/dist/common/collections/executions.d.ts +44 -1
- package/dist/common/collections/executions.js +63 -1
- package/dist/common/collections/flow_nodes.d.ts +1 -0
- package/dist/common/collections/flow_nodes.js +1 -0
- package/dist/common/collections/jobs.d.ts +1 -0
- package/dist/common/collections/jobs.js +8 -0
- package/dist/common/collections/userWorkflowTasks.d.ts +1 -0
- package/dist/common/collections/userWorkflowTasks.js +1 -0
- package/dist/common/collections/workflowCategories.d.ts +1 -0
- package/dist/common/collections/workflowCategories.js +1 -0
- package/dist/common/collections/workflowCategoryRelations.d.ts +1 -0
- package/dist/common/collections/workflowCategoryRelations.js +1 -0
- package/dist/common/collections/workflowStats.d.ts +1 -0
- package/dist/common/collections/workflowStats.js +1 -0
- package/dist/common/collections/workflowTasks.js +1 -0
- package/dist/common/collections/workflowVersionStats.d.ts +1 -0
- package/dist/common/collections/workflowVersionStats.js +1 -0
- package/dist/common/collections/workflows.d.ts +66 -11
- package/dist/common/collections/workflows.js +35 -2
- package/dist/common/constants.d.ts +5 -0
- package/dist/common/constants.js +7 -0
- package/dist/externalVersion.js +15 -13
- package/dist/locale/de-DE.json +4 -0
- package/dist/locale/en-US.json +7 -0
- package/dist/locale/es-ES.json +4 -0
- package/dist/locale/fr-FR.json +4 -0
- package/dist/locale/hu-HU.json +7 -3
- package/dist/locale/id-ID.json +4 -0
- package/dist/locale/it-IT.json +4 -0
- package/dist/locale/ja-JP.json +5 -1
- package/dist/locale/ko-KR.json +4 -0
- package/dist/locale/nl-NL.json +7 -3
- package/dist/locale/pt-BR.json +4 -0
- package/dist/locale/ru-RU.json +4 -0
- package/dist/locale/tr-TR.json +4 -0
- package/dist/locale/uk-UA.json +7 -3
- package/dist/locale/vi-VN.json +7 -3
- package/dist/locale/zh-CN.json +10 -0
- package/dist/locale/zh-TW.json +7 -3
- package/dist/node_modules/cron-parser/lib/parser.js +1 -1
- package/dist/node_modules/cron-parser/package.json +1 -1
- package/dist/node_modules/joi/dist/joi-browser.min.js +1 -0
- package/dist/node_modules/joi/lib/annotate.js +175 -0
- package/dist/node_modules/joi/lib/base.js +1069 -0
- package/dist/node_modules/joi/lib/cache.js +143 -0
- package/dist/node_modules/joi/lib/common.js +216 -0
- package/dist/node_modules/joi/lib/compile.js +283 -0
- package/dist/node_modules/joi/lib/errors.js +271 -0
- package/dist/node_modules/joi/lib/extend.js +312 -0
- package/dist/node_modules/joi/lib/index.d.ts +2365 -0
- package/dist/node_modules/joi/lib/index.js +1 -0
- package/dist/node_modules/joi/lib/manifest.js +476 -0
- package/dist/node_modules/joi/lib/messages.js +178 -0
- package/dist/node_modules/joi/lib/modify.js +267 -0
- package/dist/node_modules/joi/lib/ref.js +414 -0
- package/dist/node_modules/joi/lib/schemas.js +302 -0
- package/dist/node_modules/joi/lib/state.js +166 -0
- package/dist/node_modules/joi/lib/template.js +463 -0
- package/dist/node_modules/joi/lib/trace.js +346 -0
- package/dist/node_modules/joi/lib/types/alternatives.js +364 -0
- package/dist/node_modules/joi/lib/types/any.js +174 -0
- package/dist/node_modules/joi/lib/types/array.js +809 -0
- package/dist/node_modules/joi/lib/types/binary.js +100 -0
- package/dist/node_modules/joi/lib/types/boolean.js +150 -0
- package/dist/node_modules/joi/lib/types/date.js +233 -0
- package/dist/node_modules/joi/lib/types/function.js +93 -0
- package/dist/node_modules/joi/lib/types/keys.js +1067 -0
- package/dist/node_modules/joi/lib/types/link.js +168 -0
- package/dist/node_modules/joi/lib/types/number.js +363 -0
- package/dist/node_modules/joi/lib/types/object.js +22 -0
- package/dist/node_modules/joi/lib/types/string.js +850 -0
- package/dist/node_modules/joi/lib/types/symbol.js +102 -0
- package/dist/node_modules/joi/lib/validator.js +750 -0
- package/dist/node_modules/joi/lib/values.js +263 -0
- package/dist/node_modules/joi/node_modules/@hapi/topo/lib/index.d.ts +60 -0
- package/dist/node_modules/joi/node_modules/@hapi/topo/lib/index.js +225 -0
- package/dist/node_modules/joi/node_modules/@hapi/topo/package.json +30 -0
- package/dist/node_modules/joi/package.json +1 -0
- package/dist/node_modules/lru-cache/dist/commonjs/diagnostics-channel.d.ts +5 -0
- package/dist/node_modules/lru-cache/dist/commonjs/diagnostics-channel.js +10 -0
- package/dist/node_modules/lru-cache/dist/commonjs/index.d.ts +1381 -0
- package/dist/node_modules/lru-cache/dist/commonjs/index.js +1692 -0
- package/dist/node_modules/lru-cache/dist/commonjs/index.min.js +1 -0
- package/dist/node_modules/lru-cache/dist/esm/browser/diagnostics-channel.d.ts +5 -0
- package/dist/node_modules/lru-cache/dist/esm/browser/diagnostics-channel.js +4 -0
- package/dist/node_modules/lru-cache/dist/esm/browser/index.d.ts +1381 -0
- package/dist/node_modules/lru-cache/dist/{mjs → esm/browser}/index.js +537 -179
- package/dist/node_modules/lru-cache/dist/esm/browser/index.min.js +2 -0
- package/dist/node_modules/lru-cache/dist/esm/diagnostics-channel.d.ts +5 -0
- package/dist/node_modules/lru-cache/dist/esm/diagnostics-channel.js +19 -0
- package/dist/node_modules/lru-cache/dist/esm/index.d.ts +1381 -0
- package/dist/node_modules/lru-cache/dist/{cjs → esm}/index.js +538 -184
- package/dist/node_modules/lru-cache/dist/esm/index.min.js +2 -0
- package/dist/node_modules/lru-cache/dist/esm/node/diagnostics-channel.d.ts +5 -0
- package/dist/node_modules/lru-cache/dist/esm/node/diagnostics-channel.js +7 -0
- package/dist/node_modules/lru-cache/dist/esm/node/index.d.ts +1381 -0
- package/dist/node_modules/lru-cache/dist/esm/node/index.js +1688 -0
- package/dist/node_modules/lru-cache/dist/esm/node/index.min.js +2 -0
- package/dist/node_modules/lru-cache/package.json +1 -1
- package/dist/node_modules/nodejs-snowflake/nodejs_snowflake.js +1 -1
- package/dist/node_modules/nodejs-snowflake/package.json +1 -1
- package/dist/server/Dispatcher.d.ts +12 -6
- package/dist/server/Dispatcher.js +309 -190
- package/dist/server/ExecutionTimeoutManager.d.ts +46 -0
- package/dist/server/ExecutionTimeoutManager.js +320 -0
- package/dist/server/Plugin.d.ts +17 -3
- package/dist/server/Plugin.js +54 -12
- package/dist/server/Processor.d.ts +64 -12
- package/dist/server/Processor.js +286 -48
- package/dist/server/RunningExecutionRegistry.d.ts +18 -0
- package/dist/server/RunningExecutionRegistry.js +48 -0
- package/dist/server/actions/executions.d.ts +4 -3
- package/dist/server/actions/executions.js +42 -21
- package/dist/server/actions/jobs.d.ts +2 -1
- package/dist/server/actions/jobs.js +28 -1
- package/dist/server/actions/nodes.d.ts +5 -0
- package/dist/server/actions/nodes.js +38 -5
- package/dist/server/actions/workflows.d.ts +6 -0
- package/dist/server/actions/workflows.js +38 -0
- package/dist/server/constants.d.ts +2 -0
- package/dist/server/constants.js +3 -0
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.js +2 -0
- package/dist/server/instructions/ConditionInstruction.d.ts +2 -0
- package/dist/server/instructions/ConditionInstruction.js +17 -0
- package/dist/server/instructions/CreateInstruction.d.ts +3 -0
- package/dist/server/instructions/CreateInstruction.js +25 -0
- package/dist/server/instructions/DestroyInstruction.d.ts +3 -0
- package/dist/server/instructions/DestroyInstruction.js +25 -0
- package/dist/server/instructions/EndInstruction.d.ts +2 -0
- package/dist/server/instructions/EndInstruction.js +4 -0
- package/dist/server/instructions/MultiConditionsInstruction.d.ts +2 -0
- package/dist/server/instructions/MultiConditionsInstruction.js +23 -0
- package/dist/server/instructions/OutputInstruction.d.ts +2 -0
- package/dist/server/instructions/OutputInstruction.js +15 -1
- package/dist/server/instructions/QueryInstruction.d.ts +3 -0
- package/dist/server/instructions/QueryInstruction.js +32 -7
- package/dist/server/instructions/UpdateInstruction.d.ts +3 -0
- package/dist/server/instructions/UpdateInstruction.js +27 -0
- package/dist/server/instructions/index.d.ts +24 -4
- package/dist/server/instructions/index.js +18 -0
- package/dist/server/migrations/20260423225800-fill-workflow-created-updated-by.d.ts +13 -0
- package/dist/server/migrations/20260423225800-fill-workflow-created-updated-by.js +57 -0
- package/dist/server/migrations/20260501120000-workflow-timeout.d.ts +13 -0
- package/dist/server/migrations/20260501120000-workflow-timeout.js +63 -0
- package/dist/server/timeout-errors.d.ts +13 -0
- package/dist/server/timeout-errors.js +47 -0
- package/dist/server/triggers/CollectionTrigger.d.ts +3 -0
- package/dist/server/triggers/CollectionTrigger.js +34 -0
- package/dist/server/triggers/ScheduleTrigger/index.d.ts +3 -0
- package/dist/server/triggers/ScheduleTrigger/index.js +18 -3
- package/dist/server/triggers/index.d.ts +3 -0
- package/dist/server/triggers/index.js +18 -0
- package/dist/server/types/Execution.d.ts +6 -0
- package/dist/server/types/Job.d.ts +3 -3
- package/dist/server/types/Workflow.d.ts +6 -1
- package/dist/server/utils.d.ts +27 -0
- package/dist/server/utils.js +142 -2
- package/dist/swagger/index.d.ts +66 -75
- package/dist/swagger/index.js +58 -67
- package/package.json +5 -4
- package/dist/client/0e458d99e9fc5e65.js +0 -10
- package/dist/client/27bd65abee87cafa.js +0 -10
- package/dist/client/478692c1637f2742.js +0 -10
- package/dist/client/f39e94207f92e352.js +0 -10
- package/dist/node_modules/lru-cache/LICENSE +0 -15
- package/dist/node_modules/lru-cache/dist/cjs/index-cjs.d.ts +0 -7
- package/dist/node_modules/lru-cache/dist/cjs/index-cjs.js +0 -1
- package/dist/node_modules/lru-cache/dist/cjs/index.d.ts +0 -807
- package/dist/node_modules/lru-cache/dist/cjs/index.min.js +0 -2
- package/dist/node_modules/lru-cache/dist/mjs/index.d.ts +0 -807
- package/dist/node_modules/lru-cache/dist/mjs/index.min.js +0 -2
- /package/dist/node_modules/lru-cache/dist/{cjs → commonjs}/package.json +0 -0
- /package/dist/node_modules/lru-cache/dist/{mjs → esm}/package.json +0 -0
|
@@ -29,22 +29,24 @@ __export(Dispatcher_exports, {
|
|
|
29
29
|
default: () => Dispatcher
|
|
30
30
|
});
|
|
31
31
|
module.exports = __toCommonJS(Dispatcher_exports);
|
|
32
|
-
var
|
|
32
|
+
var import_node_crypto = require("node:crypto");
|
|
33
33
|
var import_sequelize = require("sequelize");
|
|
34
34
|
var import_constants = require("./constants");
|
|
35
35
|
var import_Plugin = require("./Plugin");
|
|
36
|
+
var import_utils = require("./utils");
|
|
37
|
+
const EXECUTION_ACQUIRE_MAX_ATTEMPTS = 5;
|
|
36
38
|
class Dispatcher {
|
|
37
39
|
constructor(plugin) {
|
|
38
40
|
this.plugin = plugin;
|
|
39
|
-
this.prepare = this.prepare.bind(this);
|
|
40
41
|
}
|
|
41
42
|
ready = false;
|
|
42
43
|
executing = null;
|
|
44
|
+
saving = null;
|
|
43
45
|
pending = [];
|
|
44
46
|
events = [];
|
|
45
47
|
eventsCount = 0;
|
|
46
48
|
get idle() {
|
|
47
|
-
return this.ready && !this.executing && !this.pending.length && !this.events.length;
|
|
49
|
+
return this.ready && !this.executing && !this.saving && !this.pending.length && !this.events.length;
|
|
48
50
|
}
|
|
49
51
|
onQueueExecution = async (event) => {
|
|
50
52
|
const ExecutionRepo = this.plugin.db.getRepository("executions");
|
|
@@ -52,11 +54,10 @@ class Dispatcher {
|
|
|
52
54
|
filterByTk: event.executionId
|
|
53
55
|
});
|
|
54
56
|
if (!execution || execution.dispatched) {
|
|
55
|
-
this.plugin.getLogger("dispatcher").info(`execution (${event.executionId}) from queue not found or not in queueing status, skip`);
|
|
56
57
|
return;
|
|
57
58
|
}
|
|
58
59
|
this.plugin.getLogger(execution.workflowId).info(`execution (${execution.id}) received from queue, adding to pending list`);
|
|
59
|
-
this.run({ execution });
|
|
60
|
+
await this.run({ execution });
|
|
60
61
|
};
|
|
61
62
|
setReady(ready) {
|
|
62
63
|
this.ready = ready;
|
|
@@ -96,11 +97,55 @@ class Dispatcher {
|
|
|
96
97
|
this.eventsCount = this.events.length;
|
|
97
98
|
logger.info(`new event triggered, now events: ${this.events.length}`);
|
|
98
99
|
logger.debug(`event data:`, { context });
|
|
99
|
-
|
|
100
|
-
|
|
100
|
+
this.saveEvent();
|
|
101
|
+
}
|
|
102
|
+
saveEvent() {
|
|
103
|
+
if (this.saving) {
|
|
101
104
|
return;
|
|
102
105
|
}
|
|
103
|
-
|
|
106
|
+
this.saving = (async () => {
|
|
107
|
+
try {
|
|
108
|
+
while (this.events.length) {
|
|
109
|
+
if (this.executing && this.plugin.db.options.dialect === "sqlite") {
|
|
110
|
+
await this.executing;
|
|
111
|
+
}
|
|
112
|
+
const event = this.events.shift();
|
|
113
|
+
this.eventsCount = this.events.length;
|
|
114
|
+
if (!event) continue;
|
|
115
|
+
const logger = this.plugin.getLogger(event[0].id);
|
|
116
|
+
logger.info(`preparing execution for event`);
|
|
117
|
+
try {
|
|
118
|
+
const execution = await this.createExecution(...event);
|
|
119
|
+
if (!execution.dispatched) {
|
|
120
|
+
if (this.plugin.serving() && !this.executing && !this.pending.length) {
|
|
121
|
+
logger.info(`local pending list is empty, adding execution (${execution.id}) to pending list`);
|
|
122
|
+
this.pending.push({ execution });
|
|
123
|
+
} else {
|
|
124
|
+
logger.info(
|
|
125
|
+
`instance is not serving as worker or local pending list is not empty, sending execution (${execution.id}) to queue`
|
|
126
|
+
);
|
|
127
|
+
try {
|
|
128
|
+
await this.plugin.app.eventQueue.publish(this.plugin.channelPendingExecution, {
|
|
129
|
+
executionId: execution.id
|
|
130
|
+
});
|
|
131
|
+
} catch (qErr) {
|
|
132
|
+
logger.error(`publishing execution (${execution.id}) to queue failed:`, { error: qErr });
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
} catch (error) {
|
|
137
|
+
logger.error(`failed to create execution:`, { error });
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
} finally {
|
|
141
|
+
this.saving = null;
|
|
142
|
+
if (this.events.length) {
|
|
143
|
+
this.saveEvent();
|
|
144
|
+
} else {
|
|
145
|
+
this.dispatch();
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
})();
|
|
104
149
|
}
|
|
105
150
|
async resume(job) {
|
|
106
151
|
let { execution } = job;
|
|
@@ -108,27 +153,37 @@ class Dispatcher {
|
|
|
108
153
|
execution = await job.getExecution();
|
|
109
154
|
}
|
|
110
155
|
this.plugin.getLogger(execution.workflowId).info(`execution (${execution.id}) resuming from job (${job.id}) added to pending list`);
|
|
111
|
-
this.run({ execution, job
|
|
156
|
+
await this.run({ execution, job });
|
|
112
157
|
}
|
|
113
158
|
async start(execution) {
|
|
114
159
|
if (execution.status) {
|
|
115
160
|
return;
|
|
116
161
|
}
|
|
117
162
|
this.plugin.getLogger(execution.workflowId).info(`starting deferred execution (${execution.id})`);
|
|
118
|
-
this.run({ execution
|
|
163
|
+
await this.run({ execution });
|
|
119
164
|
}
|
|
120
165
|
async beforeStop() {
|
|
121
166
|
this.ready = false;
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
167
|
+
this.plugin.getLogger("dispatcher").info("app is stopping, draining local queues...");
|
|
168
|
+
while (this.saving || this.executing || this.events.length || this.pending.length) {
|
|
169
|
+
if (this.saving) {
|
|
170
|
+
await this.saving;
|
|
171
|
+
}
|
|
172
|
+
if (this.executing) {
|
|
173
|
+
await this.executing;
|
|
174
|
+
}
|
|
175
|
+
if (this.events.length && !this.saving) {
|
|
176
|
+
this.saveEvent();
|
|
177
|
+
}
|
|
178
|
+
if (this.pending.length && !this.executing) {
|
|
179
|
+
this.dispatch();
|
|
180
|
+
}
|
|
181
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
127
182
|
}
|
|
183
|
+
this.plugin.getLogger("dispatcher").info("local queues drained");
|
|
128
184
|
}
|
|
129
185
|
dispatch() {
|
|
130
|
-
if (!this.ready) {
|
|
131
|
-
this.plugin.getLogger("dispatcher").warn(`app is not ready, new dispatching will be ignored`);
|
|
186
|
+
if (!this.ready && !this.pending.length && !this.events.length) {
|
|
132
187
|
return;
|
|
133
188
|
}
|
|
134
189
|
if (this.executing) {
|
|
@@ -136,30 +191,36 @@ class Dispatcher {
|
|
|
136
191
|
return;
|
|
137
192
|
}
|
|
138
193
|
if (this.events.length) {
|
|
139
|
-
|
|
194
|
+
this.saveEvent();
|
|
195
|
+
return;
|
|
140
196
|
}
|
|
141
197
|
this.executing = (async () => {
|
|
142
198
|
let next = null;
|
|
143
|
-
|
|
144
|
-
if (this.
|
|
145
|
-
const
|
|
146
|
-
|
|
199
|
+
const pending = this.pending.shift() ?? null;
|
|
200
|
+
if (pending || this.ready && this.plugin.serving()) {
|
|
201
|
+
const execution = await this.prepare((pending == null ? void 0 : pending.execution) ?? null, {
|
|
202
|
+
immediate: pending == null ? void 0 : pending.immediate
|
|
203
|
+
});
|
|
147
204
|
if (execution) {
|
|
148
|
-
next = [execution, pending.job];
|
|
205
|
+
next = [execution, pending == null ? void 0 : pending.job, pending == null ? void 0 : pending.rerun];
|
|
206
|
+
}
|
|
207
|
+
if (pending && next) {
|
|
149
208
|
this.plugin.getLogger(next[0].workflowId).info(`pending execution (${next[0].id}) ready to process`);
|
|
150
209
|
}
|
|
151
210
|
} else {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
next = [execution];
|
|
156
|
-
}
|
|
157
|
-
} else {
|
|
158
|
-
this.plugin.getLogger("dispatcher").warn(`${import_Plugin.WORKER_JOB_WORKFLOW_PROCESS} is not serving on this instance, new dispatching will be ignored`);
|
|
159
|
-
}
|
|
211
|
+
this.plugin.getLogger("dispatcher").warn(
|
|
212
|
+
`${import_Plugin.WORKER_JOB_WORKFLOW_PROCESS} is not serving on this instance or app not ready, new dispatching will be ignored`
|
|
213
|
+
);
|
|
160
214
|
}
|
|
161
215
|
if (next) {
|
|
162
|
-
|
|
216
|
+
try {
|
|
217
|
+
await this.process(next[0], next[1], { rerun: next[2] });
|
|
218
|
+
} catch (error) {
|
|
219
|
+
this.plugin.getLogger(next[0].workflowId).error(`execution (${next[0].id}) process failed`, { error });
|
|
220
|
+
if (pending && (0, import_utils.isLockAcquireError)(error)) {
|
|
221
|
+
this.pending.unshift({ ...pending, execution: next[0], immediate: true });
|
|
222
|
+
}
|
|
223
|
+
}
|
|
163
224
|
}
|
|
164
225
|
setImmediate(() => {
|
|
165
226
|
this.executing = null;
|
|
@@ -171,7 +232,10 @@ class Dispatcher {
|
|
|
171
232
|
})();
|
|
172
233
|
}
|
|
173
234
|
async run(pending) {
|
|
174
|
-
this.pending.push(
|
|
235
|
+
this.pending.push({
|
|
236
|
+
...pending,
|
|
237
|
+
immediate: !this.executing && !this.pending.length && !this.saving && !this.events.length
|
|
238
|
+
});
|
|
175
239
|
this.dispatch();
|
|
176
240
|
}
|
|
177
241
|
async triggerSync(workflow, context, { deferred, ...options } = {}) {
|
|
@@ -179,13 +243,21 @@ class Dispatcher {
|
|
|
179
243
|
try {
|
|
180
244
|
execution = await this.createExecution(workflow, context, options);
|
|
181
245
|
} catch (err) {
|
|
182
|
-
|
|
246
|
+
if (err instanceof Error) {
|
|
247
|
+
this.plugin.getLogger(workflow.id).error(`creating execution failed: ${err.message}`, err);
|
|
248
|
+
}
|
|
183
249
|
return null;
|
|
184
250
|
}
|
|
185
251
|
try {
|
|
186
|
-
|
|
252
|
+
const entered = await this.prepare(execution);
|
|
253
|
+
if (!entered) {
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
return this.process(entered, void 0, options);
|
|
187
257
|
} catch (err) {
|
|
188
|
-
|
|
258
|
+
if (err instanceof Error) {
|
|
259
|
+
this.plugin.getLogger(execution.workflowId).error(`execution (${execution.id}) error: ${err.message}`, err);
|
|
260
|
+
}
|
|
189
261
|
}
|
|
190
262
|
return null;
|
|
191
263
|
}
|
|
@@ -195,19 +267,18 @@ class Dispatcher {
|
|
|
195
267
|
if (!triggerValid) {
|
|
196
268
|
return false;
|
|
197
269
|
}
|
|
198
|
-
const { stack } = options;
|
|
270
|
+
const { stack = [] } = options;
|
|
199
271
|
let valid = true;
|
|
200
|
-
if (
|
|
272
|
+
if (stack == null ? void 0 : stack.length) {
|
|
201
273
|
const existed = await workflow.countExecutions({
|
|
202
274
|
where: {
|
|
203
275
|
id: stack
|
|
204
|
-
}
|
|
205
|
-
transaction: options.transaction
|
|
276
|
+
}
|
|
206
277
|
});
|
|
207
278
|
const limitCount = workflow.options.stackLimit || 1;
|
|
208
279
|
if (existed >= limitCount) {
|
|
209
280
|
this.plugin.getLogger(workflow.id).warn(
|
|
210
|
-
`workflow ${workflow.id} has already been triggered in stacks executions (${stack}), and max call
|
|
281
|
+
`workflow ${workflow.id} has already been triggered in stacks executions (${stack}), and max call count is ${limitCount}, newly triggering will be skipped.`
|
|
211
282
|
);
|
|
212
283
|
valid = false;
|
|
213
284
|
}
|
|
@@ -217,187 +288,235 @@ class Dispatcher {
|
|
|
217
288
|
async createExecution(workflow, context, options) {
|
|
218
289
|
var _a;
|
|
219
290
|
const { deferred } = options;
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
291
|
+
let stack = options.stack;
|
|
292
|
+
if (options.parentExecutionId && !stack) {
|
|
293
|
+
const parentExecution = await this.plugin.db.getRepository("executions").findOne({
|
|
294
|
+
filterByTk: options.parentExecutionId
|
|
295
|
+
});
|
|
296
|
+
stack = parentExecution ? [...parentExecution.stack ?? [], parentExecution.id] : [];
|
|
297
|
+
}
|
|
298
|
+
const valid = await this.validateEvent(workflow, context, { ...options, stack });
|
|
223
299
|
if (!valid) {
|
|
224
|
-
if (!sameTransaction) {
|
|
225
|
-
await transaction.commit();
|
|
226
|
-
}
|
|
227
300
|
(_a = options.onTriggerFail) == null ? void 0 : _a.call(options, workflow, context, options);
|
|
228
|
-
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
manually: options.manually
|
|
241
|
-
},
|
|
242
|
-
{ transaction }
|
|
243
|
-
);
|
|
244
|
-
} catch (err) {
|
|
245
|
-
if (!sameTransaction) {
|
|
246
|
-
await transaction.rollback();
|
|
247
|
-
}
|
|
248
|
-
throw err;
|
|
249
|
-
}
|
|
301
|
+
throw new Error("event is not valid");
|
|
302
|
+
}
|
|
303
|
+
const execution = await workflow.createExecution({
|
|
304
|
+
context,
|
|
305
|
+
key: workflow.key,
|
|
306
|
+
eventKey: options.eventKey ?? (0, import_node_crypto.randomUUID)(),
|
|
307
|
+
stack,
|
|
308
|
+
parentExecutionId: options.parentExecutionId ?? null,
|
|
309
|
+
dispatched: deferred ?? false,
|
|
310
|
+
status: deferred ? import_constants.EXECUTION_STATUS.STARTED : import_constants.EXECUTION_STATUS.QUEUEING,
|
|
311
|
+
manually: options.manually
|
|
312
|
+
});
|
|
250
313
|
this.plugin.getLogger(workflow.id).info(`execution of workflow ${workflow.id} created as ${execution.id}`);
|
|
251
314
|
if (!workflow.stats) {
|
|
252
|
-
workflow.stats = await workflow.getStats(
|
|
315
|
+
workflow.stats = await workflow.getStats();
|
|
253
316
|
}
|
|
254
|
-
await workflow.stats.increment("executed"
|
|
317
|
+
await workflow.stats.increment("executed");
|
|
255
318
|
if (this.plugin.db.options.dialect !== "postgres") {
|
|
256
|
-
await workflow.stats.reload(
|
|
319
|
+
await workflow.stats.reload();
|
|
257
320
|
}
|
|
258
321
|
if (!workflow.versionStats) {
|
|
259
|
-
workflow.versionStats = await workflow.getVersionStats(
|
|
322
|
+
workflow.versionStats = await workflow.getVersionStats();
|
|
260
323
|
}
|
|
261
|
-
await workflow.versionStats.increment("executed"
|
|
324
|
+
await workflow.versionStats.increment("executed");
|
|
262
325
|
if (this.plugin.db.options.dialect !== "postgres") {
|
|
263
|
-
await workflow.versionStats.reload(
|
|
264
|
-
}
|
|
265
|
-
if (!sameTransaction) {
|
|
266
|
-
await transaction.commit();
|
|
326
|
+
await workflow.versionStats.reload();
|
|
267
327
|
}
|
|
268
328
|
execution.workflow = workflow;
|
|
269
329
|
return execution;
|
|
270
330
|
}
|
|
271
|
-
prepare =
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
331
|
+
async prepare(input, options = {}) {
|
|
332
|
+
const logger = input ? this.plugin.getLogger(input.workflowId) : this.plugin.getLogger("dispatcher");
|
|
333
|
+
if (options.transaction) {
|
|
334
|
+
try {
|
|
335
|
+
const { execution } = await this.acquireExecution(input, options, options.transaction);
|
|
336
|
+
return execution;
|
|
337
|
+
} catch (error) {
|
|
338
|
+
if (error instanceof Error) {
|
|
339
|
+
logger.error(`entering execution failed: ${error.message}`, { error });
|
|
340
|
+
}
|
|
341
|
+
return null;
|
|
342
|
+
}
|
|
280
343
|
}
|
|
281
|
-
|
|
282
|
-
logger.info(`preparing execution for event`);
|
|
344
|
+
let result = null;
|
|
283
345
|
try {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
} else {
|
|
290
|
-
logger.info(
|
|
291
|
-
`instance is not serving as worker or local pending list is not empty, sending execution (${execution.id}) to queue`
|
|
292
|
-
);
|
|
346
|
+
await this.acquireWithRetry(
|
|
347
|
+
async () => {
|
|
348
|
+
const tx = await this.plugin.db.sequelize.transaction({
|
|
349
|
+
isolationLevel: this.plugin.db.options.dialect === "sqlite" ? void 0 : import_sequelize.Transaction.ISOLATION_LEVELS.REPEATABLE_READ
|
|
350
|
+
});
|
|
293
351
|
try {
|
|
294
|
-
await this.
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
352
|
+
const { execution, shouldRetry } = await this.acquireExecution(input, options, tx);
|
|
353
|
+
await tx.commit();
|
|
354
|
+
result = execution;
|
|
355
|
+
return shouldRetry;
|
|
356
|
+
} catch (error) {
|
|
357
|
+
await tx.rollback();
|
|
358
|
+
if (this.isConcurrentAcquireError(error)) {
|
|
359
|
+
throw error;
|
|
360
|
+
}
|
|
361
|
+
if (error instanceof Error) {
|
|
362
|
+
logger.error(`entering execution failed: ${error.message}`, { error });
|
|
363
|
+
}
|
|
364
|
+
result = null;
|
|
365
|
+
return false;
|
|
299
366
|
}
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
logger,
|
|
370
|
+
conflictMessage: input ? `acquiring pending execution (${input.id}) conflicted with another worker, retrying` : `acquiring execution conflicted with another worker, retrying`,
|
|
371
|
+
maxAttemptsMessage: input ? `acquiring pending execution (${input.id}) reached max retry attempts` : `acquiring execution reached max retry attempts, will retry on next dispatch`
|
|
300
372
|
}
|
|
301
|
-
|
|
373
|
+
);
|
|
302
374
|
} catch (error) {
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
if (this.events.length) {
|
|
306
|
-
await this.prepare();
|
|
307
|
-
} else {
|
|
308
|
-
this.plugin.getLogger("dispatcher").info("no more events need to be prepared, dispatching...");
|
|
309
|
-
if (this.executing) {
|
|
310
|
-
await this.executing;
|
|
375
|
+
if (error instanceof Error) {
|
|
376
|
+
logger.error(`acquiring execution failed: ${error.message}`, { error });
|
|
311
377
|
}
|
|
312
|
-
|
|
378
|
+
return null;
|
|
313
379
|
}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
await this.plugin.db.sequelize.transaction({ isolationLevel }, async (transaction) => {
|
|
321
|
-
const ExecutionModelClass = this.plugin.db.getModel("executions");
|
|
322
|
-
const [affected] = await ExecutionModelClass.update(
|
|
323
|
-
{ dispatched: true, status: import_constants.EXECUTION_STATUS.STARTED },
|
|
324
|
-
{
|
|
325
|
-
where: {
|
|
326
|
-
id: execution.id,
|
|
327
|
-
dispatched: false
|
|
328
|
-
},
|
|
329
|
-
transaction
|
|
330
|
-
}
|
|
331
|
-
);
|
|
332
|
-
if (!affected) {
|
|
333
|
-
fetched = null;
|
|
334
|
-
return;
|
|
335
|
-
}
|
|
380
|
+
return result;
|
|
381
|
+
}
|
|
382
|
+
async acquireExecution(input, options, transaction) {
|
|
383
|
+
let execution = input;
|
|
384
|
+
if (execution) {
|
|
385
|
+
if (!options.immediate || execution.status !== import_constants.EXECUTION_STATUS.QUEUEING) {
|
|
336
386
|
await execution.reload({ transaction });
|
|
387
|
+
}
|
|
388
|
+
} else {
|
|
389
|
+
execution = await this.plugin.db.getRepository("executions").findOne({
|
|
390
|
+
filter: {
|
|
391
|
+
dispatched: false,
|
|
392
|
+
"workflow.enabled": true
|
|
393
|
+
},
|
|
394
|
+
sort: "id",
|
|
395
|
+
transaction,
|
|
396
|
+
lock: transaction.LOCK.UPDATE,
|
|
397
|
+
skipLocked: true
|
|
337
398
|
});
|
|
338
|
-
|
|
339
|
-
|
|
399
|
+
if (execution) {
|
|
400
|
+
this.plugin.getLogger(execution.workflowId).info(`execution (${execution.id}) fetched from db`);
|
|
401
|
+
} else {
|
|
402
|
+
this.plugin.getLogger("dispatcher").debug(`no execution in db queued to process`);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
if (!execution) {
|
|
406
|
+
return { execution: null, shouldRetry: false };
|
|
340
407
|
}
|
|
341
|
-
|
|
408
|
+
const entered = await this.enter(execution, transaction);
|
|
409
|
+
const shouldRetry = !input && !entered;
|
|
410
|
+
return { execution: entered, shouldRetry };
|
|
342
411
|
}
|
|
343
|
-
async
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
async (transaction) => {
|
|
352
|
-
const execution = await this.plugin.db.getRepository("executions").findOne({
|
|
353
|
-
filter: {
|
|
354
|
-
dispatched: false,
|
|
355
|
-
"workflow.enabled": true
|
|
356
|
-
},
|
|
357
|
-
sort: "id",
|
|
358
|
-
transaction
|
|
359
|
-
});
|
|
360
|
-
if (execution) {
|
|
361
|
-
this.plugin.getLogger(execution.workflowId).info(`execution (${execution.id}) fetched from db`);
|
|
362
|
-
await execution.update(
|
|
363
|
-
{
|
|
364
|
-
dispatched: true,
|
|
365
|
-
status: import_constants.EXECUTION_STATUS.STARTED
|
|
366
|
-
},
|
|
367
|
-
{ transaction }
|
|
368
|
-
);
|
|
369
|
-
execution.workflow = this.plugin.enabledCache.get(execution.workflowId);
|
|
370
|
-
fetched = execution;
|
|
371
|
-
} else {
|
|
372
|
-
this.plugin.getLogger("dispatcher").debug(`no execution in db queued to process`);
|
|
373
|
-
}
|
|
412
|
+
async acquireWithRetry(acquire, options) {
|
|
413
|
+
for (let attempt = 1; attempt <= EXECUTION_ACQUIRE_MAX_ATTEMPTS; attempt++) {
|
|
414
|
+
let shouldRetry = false;
|
|
415
|
+
try {
|
|
416
|
+
shouldRetry = await acquire();
|
|
417
|
+
} catch (error) {
|
|
418
|
+
if (!this.isConcurrentAcquireError(error)) {
|
|
419
|
+
throw error;
|
|
374
420
|
}
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
421
|
+
shouldRetry = true;
|
|
422
|
+
options.logger.warn(options.conflictMessage, { error });
|
|
423
|
+
}
|
|
424
|
+
if (!shouldRetry) {
|
|
425
|
+
break;
|
|
426
|
+
}
|
|
427
|
+
if (attempt >= EXECUTION_ACQUIRE_MAX_ATTEMPTS) {
|
|
428
|
+
options.logger.warn(options.maxAttemptsMessage);
|
|
429
|
+
break;
|
|
430
|
+
}
|
|
378
431
|
}
|
|
379
|
-
return fetched;
|
|
380
432
|
}
|
|
381
|
-
async
|
|
382
|
-
|
|
383
|
-
|
|
433
|
+
async enter(execution, transaction) {
|
|
434
|
+
const workflow = execution.workflow || this.plugin.enabledCache.get(execution.workflowId) || await execution.getWorkflow({ transaction });
|
|
435
|
+
if (!workflow) {
|
|
436
|
+
this.plugin.getLogger(execution.workflowId).warn(`workflow (${execution.workflowId}) not found for execution`, {
|
|
437
|
+
workflowId: execution.workflowId,
|
|
438
|
+
executionId: execution.id
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
if (execution.status && execution.status !== import_constants.EXECUTION_STATUS.STARTED) {
|
|
442
|
+
return null;
|
|
443
|
+
}
|
|
444
|
+
if (execution.dispatched && execution.status === import_constants.EXECUTION_STATUS.STARTED && execution.startedAt) {
|
|
445
|
+
execution.workflow = workflow;
|
|
446
|
+
return execution;
|
|
447
|
+
}
|
|
448
|
+
const values = {
|
|
449
|
+
dispatched: true,
|
|
450
|
+
status: import_constants.EXECUTION_STATUS.STARTED
|
|
451
|
+
};
|
|
452
|
+
const where = {
|
|
453
|
+
id: execution.id,
|
|
454
|
+
status: execution.status ?? null
|
|
455
|
+
};
|
|
384
456
|
if (!execution.dispatched) {
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
457
|
+
where.dispatched = false;
|
|
458
|
+
}
|
|
459
|
+
if (!execution.startedAt) {
|
|
460
|
+
const startedAt = /* @__PURE__ */ new Date();
|
|
461
|
+
values.startedAt = startedAt;
|
|
462
|
+
execution.workflow = workflow;
|
|
463
|
+
values.expiresAt = this.plugin.timeoutManager.getExpiresAt(execution, startedAt);
|
|
464
|
+
where.startedAt = null;
|
|
465
|
+
}
|
|
466
|
+
const ExecutionModelClass = this.plugin.db.getModel("executions");
|
|
467
|
+
const [affected] = await ExecutionModelClass.update(values, {
|
|
468
|
+
where,
|
|
469
|
+
transaction
|
|
470
|
+
});
|
|
471
|
+
if (!affected) {
|
|
472
|
+
return null;
|
|
388
473
|
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
474
|
+
await execution.reload({ transaction });
|
|
475
|
+
execution.workflow = workflow;
|
|
476
|
+
return execution;
|
|
477
|
+
}
|
|
478
|
+
isConcurrentAcquireError(error) {
|
|
479
|
+
var _a, _b, _c, _d;
|
|
480
|
+
if (!(error instanceof Error)) {
|
|
481
|
+
return false;
|
|
482
|
+
}
|
|
483
|
+
const databaseError = error;
|
|
484
|
+
const code = ((_a = databaseError.parent) == null ? void 0 : _a.code) || ((_b = databaseError.original) == null ? void 0 : _b.code);
|
|
485
|
+
const errno = ((_c = databaseError.parent) == null ? void 0 : _c.errno) || ((_d = databaseError.original) == null ? void 0 : _d.errno);
|
|
486
|
+
return code === "40001" || code === "40P01" || code === "ER_LOCK_DEADLOCK" || errno === 1205 || errno === 1213;
|
|
487
|
+
}
|
|
488
|
+
async process(execution, job = null, options = {}) {
|
|
489
|
+
const { rerun, ...processorOptions } = options;
|
|
490
|
+
const logger = this.plugin.getLogger(execution.workflowId);
|
|
491
|
+
const run = async () => {
|
|
492
|
+
var _a, _b, _c;
|
|
493
|
+
if (!execution.dispatched) {
|
|
494
|
+
await execution.update({ dispatched: true, status: import_constants.EXECUTION_STATUS.STARTED });
|
|
495
|
+
logger.info(`execution (${execution.id}) from pending list updated to started`);
|
|
397
496
|
}
|
|
398
|
-
|
|
399
|
-
|
|
497
|
+
this.plugin.timeoutManager.scheduleExecutionTimeout(execution);
|
|
498
|
+
const processor = this.plugin.createProcessor(execution, processorOptions);
|
|
499
|
+
logger.info(`execution (${execution.id}) ${rerun ? "rerunning" : job ? "resuming" : "starting"}...`);
|
|
500
|
+
try {
|
|
501
|
+
await (rerun ? processor.rerun(rerun) : job ? processor.resume(job) : processor.start());
|
|
502
|
+
logger.info(`execution (${execution.id}) finished with status: ${execution.status}`);
|
|
503
|
+
logger.debug(`execution (${execution.id}) details:`, { execution });
|
|
504
|
+
if (execution.status && ((_c = (_b = (_a = execution.workflow) == null ? void 0 : _a.options) == null ? void 0 : _b.deleteExecutionOnStatus) == null ? void 0 : _c.includes(execution.status))) {
|
|
505
|
+
await execution.destroy();
|
|
506
|
+
}
|
|
507
|
+
} catch (err) {
|
|
508
|
+
if (err instanceof Error) {
|
|
509
|
+
logger.error(`execution (${execution.id}) error: ${err.message}`, err);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
return processor;
|
|
513
|
+
};
|
|
514
|
+
const lock = await this.plugin.app.lockManager.tryAcquire((0, import_utils.getExecutionLockKey)(execution.id), 6e4);
|
|
515
|
+
try {
|
|
516
|
+
return await lock.runExclusive(run, 6e4);
|
|
517
|
+
} catch (error) {
|
|
518
|
+
logger.error(`execution (${execution.id}) could not acquire process lock`, { error });
|
|
519
|
+
throw error;
|
|
400
520
|
}
|
|
401
|
-
return processor;
|
|
402
521
|
}
|
|
403
522
|
}
|