@nocobase/plugin-workflow 0.7.0-alpha.0
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/LICENSE +201 -0
- package/esm/actions/flow_nodes.d.ts +3 -0
- package/esm/actions/flow_nodes.js +139 -0
- package/esm/actions/flow_nodes.js.map +1 -0
- package/esm/actions/index.d.ts +1 -0
- package/esm/actions/index.js +8 -0
- package/esm/actions/index.js.map +1 -0
- package/esm/calculators/index.d.ts +38 -0
- package/esm/calculators/index.js +128 -0
- package/esm/calculators/index.js.map +1 -0
- package/esm/collections/executions.d.ts +3 -0
- package/esm/collections/executions.js +38 -0
- package/esm/collections/executions.js.map +1 -0
- package/esm/collections/flow_nodes.d.ts +3 -0
- package/esm/collections/flow_nodes.js +72 -0
- package/esm/collections/flow_nodes.js.map +1 -0
- package/esm/collections/jobs.d.ts +3 -0
- package/esm/collections/jobs.js +47 -0
- package/esm/collections/jobs.js.map +1 -0
- package/esm/collections/workflows.d.ts +3 -0
- package/esm/collections/workflows.js +63 -0
- package/esm/collections/workflows.js.map +1 -0
- package/esm/constants.d.ts +17 -0
- package/esm/constants.js +18 -0
- package/esm/constants.js.map +1 -0
- package/esm/index.d.ts +5 -0
- package/esm/index.js +6 -0
- package/esm/index.js.map +1 -0
- package/esm/instructions/calculation.d.ts +8 -0
- package/esm/instructions/calculation.js +55 -0
- package/esm/instructions/calculation.js.map +1 -0
- package/esm/instructions/condition.d.ts +5 -0
- package/esm/instructions/condition.js +99 -0
- package/esm/instructions/condition.js.map +1 -0
- package/esm/instructions/create.d.ts +8 -0
- package/esm/instructions/create.js +25 -0
- package/esm/instructions/create.js.map +1 -0
- package/esm/instructions/destroy.d.ts +8 -0
- package/esm/instructions/destroy.js +25 -0
- package/esm/instructions/destroy.js.map +1 -0
- package/esm/instructions/index.d.ts +15 -0
- package/esm/instructions/index.js +20 -0
- package/esm/instructions/index.js.map +1 -0
- package/esm/instructions/parallel.d.ts +13 -0
- package/esm/instructions/parallel.js +88 -0
- package/esm/instructions/parallel.js.map +1 -0
- package/esm/instructions/prompt.d.ts +7 -0
- package/esm/instructions/prompt.js +13 -0
- package/esm/instructions/prompt.js.map +1 -0
- package/esm/instructions/query.d.ts +8 -0
- package/esm/instructions/query.js +25 -0
- package/esm/instructions/query.js.map +1 -0
- package/esm/instructions/update.d.ts +8 -0
- package/esm/instructions/update.js +25 -0
- package/esm/instructions/update.js.map +1 -0
- package/esm/models/Execution.d.ts +50 -0
- package/esm/models/Execution.js +250 -0
- package/esm/models/Execution.js.map +1 -0
- package/esm/models/FlowNode.d.ts +17 -0
- package/esm/models/FlowNode.js +4 -0
- package/esm/models/FlowNode.js.map +1 -0
- package/esm/models/Job.d.ts +15 -0
- package/esm/models/Job.js +4 -0
- package/esm/models/Job.js.map +1 -0
- package/esm/models/Workflow.d.ts +27 -0
- package/esm/models/Workflow.js +72 -0
- package/esm/models/Workflow.js.map +1 -0
- package/esm/server.d.ts +5 -0
- package/esm/server.js +62 -0
- package/esm/server.js.map +1 -0
- package/esm/triggers/index.d.ts +9 -0
- package/esm/triggers/index.js +6 -0
- package/esm/triggers/index.js.map +1 -0
- package/esm/triggers/model.d.ts +12 -0
- package/esm/triggers/model.js +47 -0
- package/esm/triggers/model.js.map +1 -0
- package/lib/actions/flow_nodes.d.ts +3 -0
- package/lib/actions/flow_nodes.js +163 -0
- package/lib/actions/flow_nodes.js.map +1 -0
- package/lib/actions/index.d.ts +1 -0
- package/lib/actions/index.js +30 -0
- package/lib/actions/index.js.map +1 -0
- package/lib/calculators/index.d.ts +38 -0
- package/lib/calculators/index.js +132 -0
- package/lib/calculators/index.js.map +1 -0
- package/lib/collections/executions.d.ts +3 -0
- package/lib/collections/executions.js +40 -0
- package/lib/collections/executions.js.map +1 -0
- package/lib/collections/flow_nodes.d.ts +3 -0
- package/lib/collections/flow_nodes.js +74 -0
- package/lib/collections/flow_nodes.js.map +1 -0
- package/lib/collections/jobs.d.ts +3 -0
- package/lib/collections/jobs.js +49 -0
- package/lib/collections/jobs.js.map +1 -0
- package/lib/collections/workflows.d.ts +3 -0
- package/lib/collections/workflows.js +65 -0
- package/lib/collections/workflows.js.map +1 -0
- package/lib/constants.d.ts +17 -0
- package/lib/constants.js +21 -0
- package/lib/constants.js.map +1 -0
- package/lib/index.d.ts +5 -0
- package/lib/index.js +23 -0
- package/lib/index.js.map +1 -0
- package/lib/instructions/calculation.d.ts +8 -0
- package/lib/instructions/calculation.js +57 -0
- package/lib/instructions/calculation.js.map +1 -0
- package/lib/instructions/condition.d.ts +5 -0
- package/lib/instructions/condition.js +120 -0
- package/lib/instructions/condition.js.map +1 -0
- package/lib/instructions/create.d.ts +8 -0
- package/lib/instructions/create.js +27 -0
- package/lib/instructions/create.js.map +1 -0
- package/lib/instructions/destroy.d.ts +8 -0
- package/lib/instructions/destroy.js +27 -0
- package/lib/instructions/destroy.js.map +1 -0
- package/lib/instructions/index.d.ts +15 -0
- package/lib/instructions/index.js +26 -0
- package/lib/instructions/index.js.map +1 -0
- package/lib/instructions/parallel.d.ts +13 -0
- package/lib/instructions/parallel.js +91 -0
- package/lib/instructions/parallel.js.map +1 -0
- package/lib/instructions/prompt.d.ts +7 -0
- package/lib/instructions/prompt.js +15 -0
- package/lib/instructions/prompt.js.map +1 -0
- package/lib/instructions/query.d.ts +8 -0
- package/lib/instructions/query.js +27 -0
- package/lib/instructions/query.js.map +1 -0
- package/lib/instructions/update.d.ts +8 -0
- package/lib/instructions/update.js +27 -0
- package/lib/instructions/update.js.map +1 -0
- package/lib/models/Execution.d.ts +50 -0
- package/lib/models/Execution.js +256 -0
- package/lib/models/Execution.js.map +1 -0
- package/lib/models/FlowNode.d.ts +17 -0
- package/lib/models/FlowNode.js +7 -0
- package/lib/models/FlowNode.js.map +1 -0
- package/lib/models/Job.d.ts +15 -0
- package/lib/models/Job.js +7 -0
- package/lib/models/Job.js.map +1 -0
- package/lib/models/Workflow.d.ts +27 -0
- package/lib/models/Workflow.js +78 -0
- package/lib/models/Workflow.js.map +1 -0
- package/lib/server.d.ts +5 -0
- package/lib/server.js +68 -0
- package/lib/server.js.map +1 -0
- package/lib/triggers/index.d.ts +9 -0
- package/lib/triggers/index.js +12 -0
- package/lib/triggers/index.js.map +1 -0
- package/lib/triggers/model.d.ts +12 -0
- package/lib/triggers/model.js +49 -0
- package/lib/triggers/model.js.map +1 -0
- package/package.json +28 -0
- package/tsconfig.build.json +9 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { JOB_STATUS } from "../constants";
|
|
11
|
+
export const PARALLEL_MODE = {
|
|
12
|
+
ALL: 'all',
|
|
13
|
+
ANY: 'any',
|
|
14
|
+
RACE: 'race'
|
|
15
|
+
};
|
|
16
|
+
const StatusGetters = {
|
|
17
|
+
[PARALLEL_MODE.ALL](result) {
|
|
18
|
+
if (result.some(j => j && j.status === JOB_STATUS.REJECTED)) {
|
|
19
|
+
return JOB_STATUS.REJECTED;
|
|
20
|
+
}
|
|
21
|
+
if (result.every(j => j && j.status === JOB_STATUS.RESOLVED)) {
|
|
22
|
+
return JOB_STATUS.RESOLVED;
|
|
23
|
+
}
|
|
24
|
+
return JOB_STATUS.PENDING;
|
|
25
|
+
},
|
|
26
|
+
[PARALLEL_MODE.ANY](result) {
|
|
27
|
+
return result.some(j => j && j.status === JOB_STATUS.RESOLVED)
|
|
28
|
+
? JOB_STATUS.RESOLVED
|
|
29
|
+
: (result.some(j => j && j.status === JOB_STATUS.PENDING)
|
|
30
|
+
? JOB_STATUS.PENDING
|
|
31
|
+
: JOB_STATUS.REJECTED);
|
|
32
|
+
},
|
|
33
|
+
[PARALLEL_MODE.RACE](result) {
|
|
34
|
+
return result.some(j => j && j.status === JOB_STATUS.RESOLVED)
|
|
35
|
+
? JOB_STATUS.RESOLVED
|
|
36
|
+
: (result.some(j => j && j.status === JOB_STATUS.REJECTED)
|
|
37
|
+
? JOB_STATUS.REJECTED
|
|
38
|
+
: JOB_STATUS.PENDING);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
export default {
|
|
42
|
+
run(prevJob, execution) {
|
|
43
|
+
var _a;
|
|
44
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
45
|
+
const branches = execution.nodes
|
|
46
|
+
.filter(item => item.upstream === this && item.branchIndex !== null)
|
|
47
|
+
.sort((a, b) => a.branchIndex - b.branchIndex);
|
|
48
|
+
const job = yield execution.saveJob({
|
|
49
|
+
status: JOB_STATUS.PENDING,
|
|
50
|
+
result: Array(branches.length).fill(null),
|
|
51
|
+
nodeId: this.id,
|
|
52
|
+
upstreamId: (_a = prevJob === null || prevJob === void 0 ? void 0 : prevJob.id) !== null && _a !== void 0 ? _a : null
|
|
53
|
+
});
|
|
54
|
+
// NOTE:
|
|
55
|
+
// use `reduce` but not `Promise.all` here to avoid racing manupulating db.
|
|
56
|
+
// for users, this is almost equivalent to `Promise.all`,
|
|
57
|
+
// because of the delay is not significant sensible.
|
|
58
|
+
// another better aspect of this is, it could handle sequenced branches in future.
|
|
59
|
+
yield branches.reduce((promise, branch) => promise.then(() => execution.run(branch, job)), Promise.resolve());
|
|
60
|
+
return execution.end(this, job);
|
|
61
|
+
});
|
|
62
|
+
},
|
|
63
|
+
resume(branchJob, execution) {
|
|
64
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
65
|
+
const job = execution.findBranchParentJob(branchJob, this);
|
|
66
|
+
const { result, status } = job;
|
|
67
|
+
// if parallel has been done (resolved / rejected), do not care newly executed branch jobs.
|
|
68
|
+
if (status !== JOB_STATUS.PENDING) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
// find the index of the node which start the branch
|
|
72
|
+
const jobNode = execution.nodesMap.get(branchJob.nodeId);
|
|
73
|
+
const { branchIndex } = execution.findBranchStartNode(jobNode);
|
|
74
|
+
const { mode = PARALLEL_MODE.ALL } = this.config || {};
|
|
75
|
+
const newResult = [...result.slice(0, branchIndex), branchJob.get(), ...result.slice(branchIndex + 1)];
|
|
76
|
+
job.set({
|
|
77
|
+
result: newResult,
|
|
78
|
+
status: StatusGetters[mode](newResult)
|
|
79
|
+
});
|
|
80
|
+
if (job.status === JOB_STATUS.PENDING) {
|
|
81
|
+
yield job.save({ transaction: execution.transaction });
|
|
82
|
+
return execution.end(this, job);
|
|
83
|
+
}
|
|
84
|
+
return job;
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
//# sourceMappingURL=parallel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parallel.js","sourceRoot":"","sources":["../../src/instructions/parallel.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAK1C,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,GAAG,EAAE,KAAK;IACV,GAAG,EAAE,KAAK;IACV,IAAI,EAAE,MAAM;CACJ,CAAC;AAEX,MAAM,aAAa,GAAG;IACpB,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,MAAM;QACxB,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,QAAQ,CAAC,EAAE;YAC3D,OAAO,UAAU,CAAC,QAAQ,CAAC;SAC5B;QACD,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,QAAQ,CAAC,EAAE;YAC5D,OAAO,UAAU,CAAC,QAAQ,CAAC;SAC5B;QACD,OAAO,UAAU,CAAC,OAAO,CAAC;IAC5B,CAAC;IACD,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,MAAM;QACxB,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,QAAQ,CAAC;YAC5D,CAAC,CAAC,UAAU,CAAC,QAAQ;YACrB,CAAC,CAAC,CACA,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,OAAO,CAAC;gBACpD,CAAC,CAAC,UAAU,CAAC,OAAO;gBACpB,CAAC,CAAC,UAAU,CAAC,QAAQ,CACxB,CAAA;IACL,CAAC;IACD,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,MAAM;QACzB,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,QAAQ,CAAC;YAC5D,CAAC,CAAC,UAAU,CAAC,QAAQ;YACrB,CAAC,CAAC,CACA,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,QAAQ,CAAC;gBACrD,CAAC,CAAC,UAAU,CAAC,QAAQ;gBACrB,CAAC,CAAC,UAAU,CAAC,OAAO,CACvB,CAAA;IACL,CAAC;CACF,CAAC;AAEF,eAAe;IACP,GAAG,CAAsB,OAAiB,EAAE,SAAyB;;;YACzE,MAAM,QAAQ,GAAG,SAAS,CAAC,KAAK;iBAC7B,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,KAAK,IAAI,IAAI,IAAI,CAAC,WAAW,KAAK,IAAI,CAAC;iBACnE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC;YAEjD,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC;gBAClC,MAAM,EAAE,UAAU,CAAC,OAAO;gBAC1B,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;gBACzC,MAAM,EAAE,IAAI,CAAC,EAAE;gBACf,UAAU,EAAE,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,EAAE,mCAAI,IAAI;aAChC,CAAC,CAAC;YAEH,QAAQ;YACR,2EAA2E;YAC3E,yDAAyD;YACzD,oDAAoD;YACpD,kFAAkF;YAClF,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAqB,EAAE,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;YAE5H,OAAO,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;;KACjC;IAEK,MAAM,CAAO,SAAS,EAAE,SAAyB;;YACrD,MAAM,GAAG,GAAG,SAAS,CAAC,mBAAmB,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;YAE3D,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;YAC/B,2FAA2F;YAC3F,IAAI,MAAM,KAAK,UAAU,CAAC,OAAO,EAAE;gBACjC,OAAO,IAAI,CAAC;aACb;YAED,oDAAoD;YACpD,MAAM,OAAO,GAAG,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YACzD,MAAM,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC;YAC/D,MAAM,EAAE,IAAI,GAAG,aAAa,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC;YAEvD,MAAM,SAAS,GAAG,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,EAAE,SAAS,CAAC,GAAG,EAAE,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC;YACvG,GAAG,CAAC,GAAG,CAAC;gBACN,MAAM,EAAE,SAAS;gBACjB,MAAM,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC;aACvC,CAAC,CAAC;YAEH,IAAI,GAAG,CAAC,MAAM,KAAK,UAAU,CAAC,OAAO,EAAE;gBACrC,MAAM,GAAG,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC;gBACvD,OAAO,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;aACjC;YAED,OAAO,GAAG,CAAC;QACb,CAAC;KAAA;CACF,CAAC","sourcesContent":["import { JOB_STATUS } from \"../constants\";\nimport ExecutionModel from \"../models/Execution\";\nimport FlowNodeModel from \"../models/FlowNode\";\nimport JobModel from \"../models/Job\";\n\nexport const PARALLEL_MODE = {\n ALL: 'all',\n ANY: 'any',\n RACE: 'race'\n} as const;\n\nconst StatusGetters = {\n [PARALLEL_MODE.ALL](result) {\n if (result.some(j => j && j.status === JOB_STATUS.REJECTED)) {\n return JOB_STATUS.REJECTED;\n }\n if (result.every(j => j && j.status === JOB_STATUS.RESOLVED)) {\n return JOB_STATUS.RESOLVED;\n }\n return JOB_STATUS.PENDING;\n },\n [PARALLEL_MODE.ANY](result) {\n return result.some(j => j && j.status === JOB_STATUS.RESOLVED)\n ? JOB_STATUS.RESOLVED\n : (\n result.some(j => j && j.status === JOB_STATUS.PENDING)\n ? JOB_STATUS.PENDING\n : JOB_STATUS.REJECTED\n )\n },\n [PARALLEL_MODE.RACE](result) {\n return result.some(j => j && j.status === JOB_STATUS.RESOLVED)\n ? JOB_STATUS.RESOLVED\n : (\n result.some(j => j && j.status === JOB_STATUS.REJECTED)\n ? JOB_STATUS.REJECTED\n : JOB_STATUS.PENDING\n )\n }\n};\n\nexport default {\n async run(this: FlowNodeModel, prevJob: JobModel, execution: ExecutionModel) {\n const branches = execution.nodes\n .filter(item => item.upstream === this && item.branchIndex !== null)\n .sort((a, b) => a.branchIndex - b.branchIndex);\n\n const job = await execution.saveJob({\n status: JOB_STATUS.PENDING,\n result: Array(branches.length).fill(null),\n nodeId: this.id,\n upstreamId: prevJob?.id ?? null\n });\n\n // NOTE:\n // use `reduce` but not `Promise.all` here to avoid racing manupulating db.\n // for users, this is almost equivalent to `Promise.all`,\n // because of the delay is not significant sensible.\n // another better aspect of this is, it could handle sequenced branches in future.\n await branches.reduce((promise: Promise<any>, branch) => promise.then(() => execution.run(branch, job)), Promise.resolve());\n\n return execution.end(this, job);\n },\n\n async resume(this, branchJob, execution: ExecutionModel) {\n const job = execution.findBranchParentJob(branchJob, this);\n\n const { result, status } = job;\n // if parallel has been done (resolved / rejected), do not care newly executed branch jobs.\n if (status !== JOB_STATUS.PENDING) {\n return null;\n }\n\n // find the index of the node which start the branch\n const jobNode = execution.nodesMap.get(branchJob.nodeId);\n const { branchIndex } = execution.findBranchStartNode(jobNode);\n const { mode = PARALLEL_MODE.ALL } = this.config || {};\n\n const newResult = [...result.slice(0, branchIndex), branchJob.get(), ...result.slice(branchIndex + 1)];\n job.set({\n result: newResult,\n status: StatusGetters[mode](newResult)\n });\n\n if (job.status === JOB_STATUS.PENDING) {\n await job.save({ transaction: execution.transaction });\n return execution.end(this, job);\n }\n\n return job;\n }\n};\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { JOB_STATUS } from "../constants";
|
|
2
|
+
export default {
|
|
3
|
+
run(input, execution) {
|
|
4
|
+
return {
|
|
5
|
+
status: JOB_STATUS.PENDING
|
|
6
|
+
};
|
|
7
|
+
},
|
|
8
|
+
resume(job, execution) {
|
|
9
|
+
job.set('status', JOB_STATUS.RESOLVED);
|
|
10
|
+
return job;
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/instructions/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,eAAe;IACb,GAAG,CAAO,KAAK,EAAE,SAAS;QACxB,OAAO;YACL,MAAM,EAAE,UAAU,CAAC,OAAO;SAC3B,CAAC;IACJ,CAAC;IAED,MAAM,CAAO,GAAG,EAAE,SAAS;QACzB,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;QACvC,OAAO,GAAG,CAAC;IACb,CAAC;CACF,CAAC","sourcesContent":["import { JOB_STATUS } from \"../constants\";\n\nexport default {\n run(this, input, execution) {\n return {\n status: JOB_STATUS.PENDING\n };\n },\n\n resume(this, job, execution) {\n job.set('status', JOB_STATUS.RESOLVED);\n return job;\n }\n};\n"]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { JOB_STATUS } from "../constants";
|
|
11
|
+
export default {
|
|
12
|
+
run(input, execution) {
|
|
13
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
14
|
+
const { collection, multiple, params = {} } = this.config;
|
|
15
|
+
const repo = this.constructor.database.getRepository(collection);
|
|
16
|
+
const options = execution.getParsedValue(params);
|
|
17
|
+
const result = yield (multiple ? repo.find : repo.findOne).call(repo, Object.assign(Object.assign({}, options), { transaction: execution.transaction }));
|
|
18
|
+
return {
|
|
19
|
+
result,
|
|
20
|
+
status: JOB_STATUS.RESOLVED
|
|
21
|
+
};
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/instructions/query.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C,eAAe;IACP,GAAG,CAAsB,KAAK,EAAE,SAAS;;YAC7C,MAAM,EACJ,UAAU,EACV,QAAQ,EACR,MAAM,GAAG,EAAE,EACZ,GAAG,IAAI,CAAC,MAAM,CAAC;YAEhB,MAAM,IAAI,GAA0B,IAAI,CAAC,WAAY,CAAC,QAAQ,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;YACzF,MAAM,OAAO,GAAG,SAAS,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;YACjD,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,kCAC/D,OAAO,KACV,WAAW,EAAE,SAAS,CAAC,WAAW,IAClC,CAAC;YAEH,OAAO;gBACL,MAAM;gBACN,MAAM,EAAE,UAAU,CAAC,QAAQ;aAC5B,CAAC;QACJ,CAAC;KAAA;CACF,CAAC","sourcesContent":["import { JOB_STATUS } from \"../constants\";\nimport FlowNodeModel from \"../models/FlowNode\";\n\nexport default {\n async run(this: FlowNodeModel, input, execution) {\n const {\n collection,\n multiple,\n params = {}\n } = this.config;\n\n const repo = (<typeof FlowNodeModel>this.constructor).database.getRepository(collection);\n const options = execution.getParsedValue(params);\n const result = await (multiple ? repo.find : repo.findOne).call(repo, {\n ...options,\n transaction: execution.transaction\n });\n\n return {\n result,\n status: JOB_STATUS.RESOLVED\n };\n }\n};\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import FlowNodeModel from "../models/FlowNode";
|
|
2
|
+
declare const _default: {
|
|
3
|
+
run(this: FlowNodeModel, input: any, execution: any): Promise<{
|
|
4
|
+
result: import("@nocobase/database").Model<any, any> | import("@nocobase/database").Model<any, any>[];
|
|
5
|
+
status: number;
|
|
6
|
+
}>;
|
|
7
|
+
};
|
|
8
|
+
export default _default;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { JOB_STATUS } from "../constants";
|
|
11
|
+
export default {
|
|
12
|
+
run(input, execution) {
|
|
13
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
14
|
+
const { collection, multiple = false, params = {} } = this.config;
|
|
15
|
+
const repo = this.constructor.database.getRepository(collection);
|
|
16
|
+
const options = execution.getParsedValue(params);
|
|
17
|
+
const result = yield repo.update(Object.assign(Object.assign({}, options), { transaction: execution.transaction }));
|
|
18
|
+
return {
|
|
19
|
+
result: multiple ? result : (result[0] || null),
|
|
20
|
+
status: JOB_STATUS.RESOLVED
|
|
21
|
+
};
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=update.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/instructions/update.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C,eAAe;IACP,GAAG,CAAsB,KAAK,EAAE,SAAS;;YAC7C,MAAM,EACJ,UAAU,EACV,QAAQ,GAAG,KAAK,EAChB,MAAM,GAAG,EAAE,EACZ,GAAG,IAAI,CAAC,MAAM,CAAC;YAEhB,MAAM,IAAI,GAA0B,IAAI,CAAC,WAAY,CAAC,QAAQ,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;YACzF,MAAM,OAAO,GAAG,SAAS,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;YACjD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,iCAC3B,OAAO,KACV,WAAW,EAAE,SAAS,CAAC,WAAW,IAClC,CAAC;YAEH,OAAO;gBACL,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;gBAC/C,MAAM,EAAE,UAAU,CAAC,QAAQ;aAC5B,CAAC;QACJ,CAAC;KAAA;CACF,CAAA","sourcesContent":["import { JOB_STATUS } from \"../constants\";\nimport FlowNodeModel from \"../models/FlowNode\";\n\nexport default {\n async run(this: FlowNodeModel, input, execution) {\n const {\n collection,\n multiple = false,\n params = {}\n } = this.config;\n\n const repo = (<typeof FlowNodeModel>this.constructor).database.getRepository(collection);\n const options = execution.getParsedValue(params);\n const result = await repo.update({\n ...options,\n transaction: execution.transaction\n });\n\n return {\n result: multiple ? result : (result[0] || null),\n status: JOB_STATUS.RESOLVED\n };\n }\n}\n"]}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Database, Model } from '@nocobase/database';
|
|
2
|
+
import { BelongsToGetAssociationMixin, HasManyGetAssociationsMixin, Transaction } from 'sequelize';
|
|
3
|
+
import WorkflowModel from './Workflow';
|
|
4
|
+
import FlowNodeModel from './FlowNode';
|
|
5
|
+
import JobModel from './Job';
|
|
6
|
+
export interface ExecutionOptions {
|
|
7
|
+
transaction?: Transaction;
|
|
8
|
+
}
|
|
9
|
+
export default class ExecutionModel extends Model {
|
|
10
|
+
static readonly database: Database;
|
|
11
|
+
id: number;
|
|
12
|
+
title: string;
|
|
13
|
+
context: any;
|
|
14
|
+
status: number;
|
|
15
|
+
useTransaction: boolean;
|
|
16
|
+
createdAt: Date;
|
|
17
|
+
updatedAt: Date;
|
|
18
|
+
workflow?: WorkflowModel;
|
|
19
|
+
getWorkflow: BelongsToGetAssociationMixin<WorkflowModel>;
|
|
20
|
+
jobs?: JobModel[];
|
|
21
|
+
getJobs: HasManyGetAssociationsMixin<JobModel>;
|
|
22
|
+
options: ExecutionOptions;
|
|
23
|
+
transaction: Transaction;
|
|
24
|
+
nodes: Array<FlowNodeModel>;
|
|
25
|
+
nodesMap: Map<number, FlowNodeModel>;
|
|
26
|
+
jobsMap: Map<number, JobModel>;
|
|
27
|
+
jobsMapByNodeId: {
|
|
28
|
+
[key: number]: any;
|
|
29
|
+
};
|
|
30
|
+
static StatusMap: {
|
|
31
|
+
[x: number]: number;
|
|
32
|
+
};
|
|
33
|
+
makeNodes(nodes?: any[]): void;
|
|
34
|
+
makeJobs(jobs: Array<JobModel>): void;
|
|
35
|
+
getTransaction(): Transaction | Promise<Transaction>;
|
|
36
|
+
prepare(options: any, commit?: boolean): Promise<void>;
|
|
37
|
+
start(options: ExecutionOptions): Promise<void>;
|
|
38
|
+
resume(job: JobModel, options: ExecutionOptions): Promise<void>;
|
|
39
|
+
private commit;
|
|
40
|
+
private exec;
|
|
41
|
+
run(node: any, input?: any): any;
|
|
42
|
+
end(node: any, job: any): any;
|
|
43
|
+
recall(node: any, job: any): any;
|
|
44
|
+
exit(job: JobModel | null): Promise<any>;
|
|
45
|
+
saveJob(payload: any): Promise<JobModel>;
|
|
46
|
+
findBranchStartNode(node: FlowNodeModel): FlowNodeModel | null;
|
|
47
|
+
findBranchParentNode(node: FlowNodeModel): FlowNodeModel | null;
|
|
48
|
+
findBranchParentJob(job: JobModel, node: FlowNodeModel): JobModel | null;
|
|
49
|
+
getParsedValue(value: any, node?: any): any;
|
|
50
|
+
}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { Model } from '@nocobase/database';
|
|
11
|
+
import parse from 'json-templates';
|
|
12
|
+
import { EXECUTION_STATUS, JOB_STATUS } from '../constants';
|
|
13
|
+
import instructions from '../instructions';
|
|
14
|
+
import calculators from '../calculators';
|
|
15
|
+
export default class ExecutionModel extends Model {
|
|
16
|
+
constructor() {
|
|
17
|
+
super(...arguments);
|
|
18
|
+
this.nodes = [];
|
|
19
|
+
this.nodesMap = new Map();
|
|
20
|
+
this.jobsMap = new Map();
|
|
21
|
+
this.jobsMapByNodeId = {};
|
|
22
|
+
}
|
|
23
|
+
// make dual linked nodes list then cache
|
|
24
|
+
makeNodes(nodes = []) {
|
|
25
|
+
this.nodes = nodes;
|
|
26
|
+
nodes.forEach((node) => {
|
|
27
|
+
this.nodesMap.set(node.id, node);
|
|
28
|
+
});
|
|
29
|
+
nodes.forEach((node) => {
|
|
30
|
+
if (node.upstreamId) {
|
|
31
|
+
node.upstream = this.nodesMap.get(node.upstreamId);
|
|
32
|
+
}
|
|
33
|
+
if (node.downstreamId) {
|
|
34
|
+
node.downstream = this.nodesMap.get(node.downstreamId);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
makeJobs(jobs) {
|
|
39
|
+
jobs.forEach((job) => {
|
|
40
|
+
this.jobsMap.set(job.id, job);
|
|
41
|
+
// TODO: should consider cycle, and from previous job
|
|
42
|
+
this.jobsMapByNodeId[job.nodeId] = job.result;
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
getTransaction() {
|
|
46
|
+
const { sequelize } = this.constructor.database;
|
|
47
|
+
// @ts-ignore
|
|
48
|
+
if (!this.useTransaction) {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
const { options } = this;
|
|
52
|
+
// @ts-ignore
|
|
53
|
+
return options.transaction && !options.transaction.finished
|
|
54
|
+
? options.transaction
|
|
55
|
+
: sequelize.transaction();
|
|
56
|
+
}
|
|
57
|
+
prepare(options, commit = false) {
|
|
58
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
59
|
+
this.options = options || {};
|
|
60
|
+
// @ts-ignore
|
|
61
|
+
const transaction = yield this.getTransaction();
|
|
62
|
+
this.transaction = transaction;
|
|
63
|
+
if (!this.workflow) {
|
|
64
|
+
this.workflow = yield this.getWorkflow({ transaction });
|
|
65
|
+
}
|
|
66
|
+
const nodes = yield this.workflow.getNodes({ transaction });
|
|
67
|
+
this.makeNodes(nodes);
|
|
68
|
+
const jobs = yield this.getJobs({
|
|
69
|
+
order: [['id', 'ASC']],
|
|
70
|
+
transaction,
|
|
71
|
+
});
|
|
72
|
+
this.makeJobs(jobs);
|
|
73
|
+
if (commit) {
|
|
74
|
+
yield this.commit();
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
start(options) {
|
|
79
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
80
|
+
if (this.status !== EXECUTION_STATUS.STARTED) {
|
|
81
|
+
throw new Error(`execution was ended with status ${this.status}`);
|
|
82
|
+
}
|
|
83
|
+
yield this.prepare(options);
|
|
84
|
+
if (this.nodes.length) {
|
|
85
|
+
const head = this.nodes.find(item => !item.upstream);
|
|
86
|
+
yield this.run(head, { result: this.context });
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
yield this.exit(null);
|
|
90
|
+
}
|
|
91
|
+
yield this.commit();
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
resume(job, options) {
|
|
95
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
96
|
+
if (this.status !== EXECUTION_STATUS.STARTED) {
|
|
97
|
+
throw new Error(`execution was ended with status ${this.status}`);
|
|
98
|
+
}
|
|
99
|
+
yield this.prepare(options);
|
|
100
|
+
const node = this.nodesMap.get(job.nodeId);
|
|
101
|
+
yield this.recall(node, job);
|
|
102
|
+
yield this.commit();
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
commit() {
|
|
106
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
107
|
+
// @ts-ignore
|
|
108
|
+
if (this.transaction && (!this.options.transaction || this.options.transaction.finished)) {
|
|
109
|
+
yield this.transaction.commit();
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
exec(instruction, node, prevJob) {
|
|
114
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
115
|
+
let job;
|
|
116
|
+
try {
|
|
117
|
+
// call instruction to get result and status
|
|
118
|
+
job = yield instruction.call(node, prevJob, this);
|
|
119
|
+
if (!job) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
catch (err) {
|
|
124
|
+
// for uncaught error, set to rejected
|
|
125
|
+
job = {
|
|
126
|
+
result: err instanceof Error
|
|
127
|
+
? { message: err.message, stack: process.env.NODE_ENV === 'production' ? [] : err.stack }
|
|
128
|
+
: err,
|
|
129
|
+
status: JOB_STATUS.REJECTED,
|
|
130
|
+
};
|
|
131
|
+
// if previous job is from resuming
|
|
132
|
+
if (prevJob && prevJob.nodeId === node.id) {
|
|
133
|
+
prevJob.set(job);
|
|
134
|
+
job = prevJob;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
let savedJob;
|
|
138
|
+
// TODO(optimize): many checking of resuming or new could be improved
|
|
139
|
+
// could be implemented separately in exec() / resume()
|
|
140
|
+
if (job instanceof Model) {
|
|
141
|
+
savedJob = (yield job.save({ transaction: this.transaction }));
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
const upstreamId = prevJob instanceof Model ? prevJob.get('id') : null;
|
|
145
|
+
savedJob = yield this.saveJob(Object.assign({ nodeId: node.id, upstreamId }, job));
|
|
146
|
+
}
|
|
147
|
+
if (savedJob.status === JOB_STATUS.RESOLVED && node.downstream) {
|
|
148
|
+
// run next node
|
|
149
|
+
return this.run(node.downstream, savedJob);
|
|
150
|
+
}
|
|
151
|
+
// all nodes in scope have been executed
|
|
152
|
+
return this.end(node, savedJob);
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
run(node, input) {
|
|
156
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
157
|
+
const { run } = instructions.get(node.type);
|
|
158
|
+
if (typeof run !== 'function') {
|
|
159
|
+
return Promise.reject(new Error('`run` should be implemented for customized execution of the node'));
|
|
160
|
+
}
|
|
161
|
+
return this.exec(run, node, input);
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
// parent node should take over the control
|
|
165
|
+
end(node, job) {
|
|
166
|
+
const parentNode = this.findBranchParentNode(node);
|
|
167
|
+
// no parent, means on main flow
|
|
168
|
+
if (parentNode) {
|
|
169
|
+
return this.recall(parentNode, job);
|
|
170
|
+
}
|
|
171
|
+
// really done for all nodes
|
|
172
|
+
// * should mark execution as done with last job status
|
|
173
|
+
return this.exit(job);
|
|
174
|
+
}
|
|
175
|
+
recall(node, job) {
|
|
176
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
177
|
+
const { resume } = instructions.get(node.type);
|
|
178
|
+
if (typeof resume !== 'function') {
|
|
179
|
+
return Promise.reject(new Error('`resume` should be implemented because the node made branch'));
|
|
180
|
+
}
|
|
181
|
+
return this.exec(resume, node, job);
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
exit(job) {
|
|
185
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
186
|
+
const status = job ? ExecutionModel.StatusMap[job.status] : EXECUTION_STATUS.RESOLVED;
|
|
187
|
+
yield this.update({ status }, { transaction: this.transaction });
|
|
188
|
+
return null;
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
// TODO(optimize)
|
|
192
|
+
saveJob(payload) {
|
|
193
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
194
|
+
const { database } = this.constructor;
|
|
195
|
+
const { model } = database.getCollection('jobs');
|
|
196
|
+
const [job] = (yield model.upsert(Object.assign(Object.assign({}, payload), { executionId: this.id }), { transaction: this.transaction }));
|
|
197
|
+
this.jobsMap.set(job.id, job);
|
|
198
|
+
this.jobsMapByNodeId[job.nodeId] = job.result;
|
|
199
|
+
return job;
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
// find the first node in current branch
|
|
203
|
+
findBranchStartNode(node) {
|
|
204
|
+
for (let n = node; n; n = n.upstream) {
|
|
205
|
+
if (n.branchIndex !== null) {
|
|
206
|
+
return n;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
// find the node start current branch
|
|
212
|
+
findBranchParentNode(node) {
|
|
213
|
+
for (let n = node; n; n = n.upstream) {
|
|
214
|
+
if (n.branchIndex !== null) {
|
|
215
|
+
return n.upstream;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
findBranchParentJob(job, node) {
|
|
221
|
+
for (let j = job; j; j = this.jobsMap.get(j.upstreamId)) {
|
|
222
|
+
if (j.nodeId === node.id) {
|
|
223
|
+
return j;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
getParsedValue(value, node) {
|
|
229
|
+
const injectedFns = {};
|
|
230
|
+
const scope = {
|
|
231
|
+
execution: this,
|
|
232
|
+
node
|
|
233
|
+
};
|
|
234
|
+
for (let [name, fn] of calculators.getEntities()) {
|
|
235
|
+
injectedFns[name] = fn.bind(scope);
|
|
236
|
+
}
|
|
237
|
+
return parse(value)({
|
|
238
|
+
$context: this.context,
|
|
239
|
+
$jobsMapByNodeId: this.jobsMapByNodeId,
|
|
240
|
+
$fn: injectedFns
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
ExecutionModel.StatusMap = {
|
|
245
|
+
[JOB_STATUS.PENDING]: EXECUTION_STATUS.STARTED,
|
|
246
|
+
[JOB_STATUS.RESOLVED]: EXECUTION_STATUS.RESOLVED,
|
|
247
|
+
[JOB_STATUS.REJECTED]: EXECUTION_STATUS.REJECTED,
|
|
248
|
+
[JOB_STATUS.CANCELLED]: EXECUTION_STATUS.CANCELLED,
|
|
249
|
+
};
|
|
250
|
+
//# sourceMappingURL=Execution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Execution.js","sourceRoot":"","sources":["../../src/models/Execution.ts"],"names":[],"mappings":"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","sourcesContent":["import { Database, Model } from '@nocobase/database';\nimport parse from 'json-templates';\nimport { BelongsToGetAssociationMixin, HasManyGetAssociationsMixin, Transaction } from 'sequelize';\nimport { EXECUTION_STATUS, JOB_STATUS } from '../constants';\nimport instructions from '../instructions';\nimport WorkflowModel from './Workflow';\nimport FlowNodeModel from './FlowNode';\nimport JobModel from './Job';\nimport calculators from '../calculators';\n\nexport interface ExecutionOptions {\n transaction?: Transaction;\n}\n\nexport default class ExecutionModel extends Model {\n declare static readonly database: Database;\n\n declare id: number;\n declare title: string;\n declare context: any;\n declare status: number;\n // NOTE: this duplicated column is for transaction in preparing cycle from workflow\n declare useTransaction: boolean;\n\n declare createdAt: Date;\n declare updatedAt: Date;\n\n declare workflow?: WorkflowModel;\n declare getWorkflow: BelongsToGetAssociationMixin<WorkflowModel>;\n\n declare jobs?: JobModel[];\n declare getJobs: HasManyGetAssociationsMixin<JobModel>;\n\n options: ExecutionOptions;\n transaction: Transaction;\n\n nodes: Array<FlowNodeModel> = [];\n nodesMap = new Map<number, FlowNodeModel>();\n jobsMap = new Map<number, JobModel>();\n jobsMapByNodeId: { [key: number]: any } = {};\n\n static StatusMap = {\n [JOB_STATUS.PENDING]: EXECUTION_STATUS.STARTED,\n [JOB_STATUS.RESOLVED]: EXECUTION_STATUS.RESOLVED,\n [JOB_STATUS.REJECTED]: EXECUTION_STATUS.REJECTED,\n [JOB_STATUS.CANCELLED]: EXECUTION_STATUS.CANCELLED,\n };\n\n // make dual linked nodes list then cache\n makeNodes(nodes = []) {\n this.nodes = nodes;\n\n nodes.forEach((node) => {\n this.nodesMap.set(node.id, node);\n });\n\n nodes.forEach((node) => {\n if (node.upstreamId) {\n node.upstream = this.nodesMap.get(node.upstreamId);\n }\n\n if (node.downstreamId) {\n node.downstream = this.nodesMap.get(node.downstreamId);\n }\n });\n }\n\n makeJobs(jobs: Array<JobModel>) {\n jobs.forEach((job) => {\n this.jobsMap.set(job.id, job);\n // TODO: should consider cycle, and from previous job\n this.jobsMapByNodeId[job.nodeId] = job.result;\n });\n }\n\n getTransaction() {\n const { sequelize } = (<typeof WorkflowModel>this.constructor).database;\n // @ts-ignore\n if (!this.useTransaction) {\n return undefined;\n }\n\n const { options } = this;\n\n // @ts-ignore\n return options.transaction && !options.transaction.finished\n ? options.transaction\n : sequelize.transaction();\n }\n\n async prepare(options, commit = false) {\n this.options = options || {};\n // @ts-ignore\n const transaction = await this.getTransaction()\n this.transaction = transaction;\n\n if (!this.workflow) {\n this.workflow = await this.getWorkflow({ transaction });\n }\n\n const nodes = await this.workflow.getNodes({ transaction });\n\n this.makeNodes(nodes);\n\n const jobs = await this.getJobs({\n order: [['id', 'ASC']],\n transaction,\n });\n\n this.makeJobs(jobs);\n\n if (commit) {\n await this.commit();\n }\n }\n\n public async start(options: ExecutionOptions) {\n if (this.status !== EXECUTION_STATUS.STARTED) {\n throw new Error(`execution was ended with status ${this.status}`);\n }\n await this.prepare(options);\n if (this.nodes.length) {\n const head = this.nodes.find(item => !item.upstream);\n await this.run(head, { result: this.context });\n } else {\n await this.exit(null);\n }\n await this.commit();\n }\n\n public async resume(job: JobModel, options: ExecutionOptions) {\n if (this.status !== EXECUTION_STATUS.STARTED) {\n throw new Error(`execution was ended with status ${this.status}`);\n }\n await this.prepare(options);\n const node = this.nodesMap.get(job.nodeId);\n await this.recall(node, job);\n await this.commit();\n }\n\n private async commit() {\n // @ts-ignore\n if (this.transaction && (!this.options.transaction || this.options.transaction.finished)) {\n await this.transaction.commit();\n }\n }\n\n private async exec(instruction: Function, node: FlowNodeModel, prevJob) {\n let job;\n try {\n // call instruction to get result and status\n job = await instruction.call(node, prevJob, this);\n if (!job) {\n return null;\n }\n } catch (err) {\n // for uncaught error, set to rejected\n job = {\n result: err instanceof Error\n ? { message: err.message, stack: process.env.NODE_ENV === 'production' ? [] : err.stack }\n : err,\n status: JOB_STATUS.REJECTED,\n };\n // if previous job is from resuming\n if (prevJob && prevJob.nodeId === node.id) {\n prevJob.set(job);\n job = prevJob;\n }\n }\n\n let savedJob;\n // TODO(optimize): many checking of resuming or new could be improved\n // could be implemented separately in exec() / resume()\n if (job instanceof Model) {\n savedJob = (await job.save({ transaction: this.transaction })) as unknown as JobModel;\n } else {\n const upstreamId = prevJob instanceof Model ? prevJob.get('id') : null;\n savedJob = await this.saveJob({\n nodeId: node.id,\n upstreamId,\n ...job,\n });\n }\n\n if (savedJob.status === JOB_STATUS.RESOLVED && node.downstream) {\n // run next node\n return this.run(node.downstream, savedJob);\n }\n\n // all nodes in scope have been executed\n return this.end(node, savedJob);\n }\n\n public async run(node, input?) {\n const { run } = instructions.get(node.type);\n if (typeof run !== 'function') {\n return Promise.reject(new Error('`run` should be implemented for customized execution of the node'));\n }\n\n return this.exec(run, node, input);\n }\n\n // parent node should take over the control\n public end(node, job) {\n const parentNode = this.findBranchParentNode(node);\n // no parent, means on main flow\n if (parentNode) {\n return this.recall(parentNode, job);\n }\n\n // really done for all nodes\n // * should mark execution as done with last job status\n return this.exit(job);\n }\n\n async recall(node, job) {\n const { resume } = instructions.get(node.type);\n if (typeof resume !== 'function') {\n return Promise.reject(new Error('`resume` should be implemented because the node made branch'));\n }\n\n return this.exec(resume, node, job);\n }\n\n async exit(job: JobModel | null) {\n const status = job ? ExecutionModel.StatusMap[job.status] : EXECUTION_STATUS.RESOLVED;\n await this.update({ status }, { transaction: this.transaction });\n return null;\n }\n\n // TODO(optimize)\n async saveJob(payload) {\n const { database } = <typeof WorkflowModel>this.constructor;\n const { model } = database.getCollection('jobs');\n const [job] = (await model.upsert(\n {\n ...payload,\n executionId: this.id,\n },\n { transaction: this.transaction },\n )) as unknown as [JobModel, boolean | null];\n this.jobsMap.set(job.id, job);\n this.jobsMapByNodeId[job.nodeId] = job.result;\n\n return job;\n }\n\n // find the first node in current branch\n findBranchStartNode(node: FlowNodeModel): FlowNodeModel | null {\n for (let n = node; n; n = n.upstream) {\n if (n.branchIndex !== null) {\n return n;\n }\n }\n return null;\n }\n\n // find the node start current branch\n findBranchParentNode(node: FlowNodeModel): FlowNodeModel | null {\n for (let n = node; n; n = n.upstream) {\n if (n.branchIndex !== null) {\n return n.upstream;\n }\n }\n return null;\n }\n\n findBranchParentJob(job: JobModel, node: FlowNodeModel): JobModel | null {\n for (let j = job; j; j = this.jobsMap.get(j.upstreamId)) {\n if (j.nodeId === node.id) {\n return j;\n }\n }\n return null;\n }\n\n public getParsedValue(value, node?) {\n const injectedFns = {};\n const scope = {\n execution: this,\n node\n };\n for (let [name, fn] of calculators.getEntities()) {\n injectedFns[name] = fn.bind(scope);\n }\n\n return parse(value)({\n $context: this.context,\n $jobsMapByNodeId: this.jobsMapByNodeId,\n $fn: injectedFns\n });\n }\n}\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Database, Model } from '@nocobase/database';
|
|
2
|
+
import { BelongsToGetAssociationMixin } from 'sequelize';
|
|
3
|
+
import WorkflowModel from './Workflow';
|
|
4
|
+
export default class FlowNodeModel extends Model {
|
|
5
|
+
static readonly database: Database;
|
|
6
|
+
id: number;
|
|
7
|
+
title: string;
|
|
8
|
+
branchIndex: null | number;
|
|
9
|
+
type: string;
|
|
10
|
+
config: any;
|
|
11
|
+
createdAt: Date;
|
|
12
|
+
updatedAt: Date;
|
|
13
|
+
upstream: FlowNodeModel;
|
|
14
|
+
downstream: FlowNodeModel;
|
|
15
|
+
workflow?: WorkflowModel;
|
|
16
|
+
getWorkflow: BelongsToGetAssociationMixin<WorkflowModel>;
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FlowNode.js","sourceRoot":"","sources":["../../src/models/FlowNode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAKrD,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,KAAK;CAiB/C","sourcesContent":["import { Database, Model } from '@nocobase/database';\nimport { BelongsToGetAssociationMixin } from 'sequelize';\nimport WorkflowModel from './Workflow';\n\n\nexport default class FlowNodeModel extends Model {\n declare static readonly database: Database;\n\n declare id: number;\n declare title: string;\n declare branchIndex: null | number;\n declare type: string;\n declare config: any;\n\n declare createdAt: Date;\n declare updatedAt: Date;\n\n declare upstream: FlowNodeModel;\n declare downstream: FlowNodeModel;\n\n declare workflow?: WorkflowModel;\n declare getWorkflow: BelongsToGetAssociationMixin<WorkflowModel>;\n}\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Model } from '@nocobase/database';
|
|
2
|
+
import { BelongsToGetAssociationMixin } from 'sequelize';
|
|
3
|
+
import FlowNodeModel from './FlowNode';
|
|
4
|
+
export default class JobModel extends Model {
|
|
5
|
+
id: number;
|
|
6
|
+
status: number;
|
|
7
|
+
result: any;
|
|
8
|
+
createdAt: Date;
|
|
9
|
+
updatedAt: Date;
|
|
10
|
+
upstreamId: number;
|
|
11
|
+
upstream: JobModel;
|
|
12
|
+
nodeId: number;
|
|
13
|
+
node?: FlowNodeModel;
|
|
14
|
+
getNode: BelongsToGetAssociationMixin<FlowNodeModel>;
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Job.js","sourceRoot":"","sources":["../../src/models/Job.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAI3C,MAAM,CAAC,OAAO,OAAO,QAAS,SAAQ,KAAK;CAc1C","sourcesContent":["import { Model } from '@nocobase/database';\nimport { BelongsToGetAssociationMixin } from 'sequelize';\nimport FlowNodeModel from './FlowNode';\n\nexport default class JobModel extends Model {\n declare id: number;\n declare status: number;\n declare result: any;\n\n declare createdAt: Date;\n declare updatedAt: Date;\n\n declare upstreamId: number;\n declare upstream: JobModel;\n\n declare nodeId: number;\n declare node?: FlowNodeModel;\n declare getNode: BelongsToGetAssociationMixin<FlowNodeModel>;\n}"]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Database, Model } from '@nocobase/database';
|
|
2
|
+
import { HasManyCreateAssociationMixin, HasManyGetAssociationsMixin } from 'sequelize';
|
|
3
|
+
import ExecutionModel from './Execution';
|
|
4
|
+
import FlowNodeModel from './FlowNode';
|
|
5
|
+
export default class WorkflowModel extends Model {
|
|
6
|
+
static database: Database;
|
|
7
|
+
id: number;
|
|
8
|
+
title: string;
|
|
9
|
+
enabled: boolean;
|
|
10
|
+
description?: string;
|
|
11
|
+
type: string;
|
|
12
|
+
config: any;
|
|
13
|
+
useTransaction: boolean;
|
|
14
|
+
createdAt: Date;
|
|
15
|
+
updatedAt: Date;
|
|
16
|
+
nodes: FlowNodeModel[];
|
|
17
|
+
getNodes: HasManyGetAssociationsMixin<FlowNodeModel>;
|
|
18
|
+
createNode: HasManyCreateAssociationMixin<FlowNodeModel>;
|
|
19
|
+
executions: ExecutionModel[];
|
|
20
|
+
getExecutions: HasManyGetAssociationsMixin<ExecutionModel>;
|
|
21
|
+
createExecution: HasManyCreateAssociationMixin<ExecutionModel>;
|
|
22
|
+
static mount(): Promise<void>;
|
|
23
|
+
getHookId(): string;
|
|
24
|
+
getTransaction(options: any): any;
|
|
25
|
+
toggle(enable?: boolean): Promise<void>;
|
|
26
|
+
trigger(context: Object, options: any): Promise<ExecutionModel>;
|
|
27
|
+
}
|