mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-05 21:49:25 +08:00
Merge branch 'next' into develop
This commit is contained in:
commit
1eb036e599
@ -108,7 +108,7 @@ export default class extends Instruction {
|
|||||||
// add to schedule
|
// add to schedule
|
||||||
this.schedule(job);
|
this.schedule(job);
|
||||||
|
|
||||||
return processor.exit();
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async resume(node, prevJob, processor: Processor) {
|
async resume(node, prevJob, processor: Processor) {
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
"dayjs": "^1.11.8",
|
"dayjs": "^1.11.8",
|
||||||
"lodash": "4.17.21",
|
"lodash": "4.17.21",
|
||||||
"lru-cache": "8.0.5",
|
"lru-cache": "8.0.5",
|
||||||
|
"nodejs-snowflake": "2.0.1",
|
||||||
"react": "18.x",
|
"react": "18.x",
|
||||||
"react-i18next": "^11.15.1",
|
"react-i18next": "^11.15.1",
|
||||||
"react-js-cron": "^3.1.0",
|
"react-js-cron": "^3.1.0",
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* This file is part of the NocoBase (R) project.
|
||||||
|
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
||||||
|
* Authors: NocoBase Team.
|
||||||
|
*
|
||||||
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
||||||
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default class Dispatcher {
|
||||||
|
constructor() {}
|
||||||
|
}
|
@ -10,6 +10,7 @@
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { randomUUID } from 'crypto';
|
import { randomUUID } from 'crypto';
|
||||||
|
|
||||||
|
import { Snowflake } from 'nodejs-snowflake';
|
||||||
import { Transaction, Transactionable } from 'sequelize';
|
import { Transaction, Transactionable } from 'sequelize';
|
||||||
import LRUCache from 'lru-cache';
|
import LRUCache from 'lru-cache';
|
||||||
|
|
||||||
@ -61,6 +62,7 @@ export default class PluginWorkflowServer extends Plugin {
|
|||||||
triggers: Registry<Trigger> = new Registry();
|
triggers: Registry<Trigger> = new Registry();
|
||||||
functions: Registry<CustomFunction> = new Registry();
|
functions: Registry<CustomFunction> = new Registry();
|
||||||
enabledCache: Map<number, WorkflowModel> = new Map();
|
enabledCache: Map<number, WorkflowModel> = new Map();
|
||||||
|
snowflake: Snowflake;
|
||||||
|
|
||||||
private ready = false;
|
private ready = false;
|
||||||
private executing: Promise<void> | null = null;
|
private executing: Promise<void> | null = null;
|
||||||
@ -219,6 +221,14 @@ export default class PluginWorkflowServer extends Plugin {
|
|||||||
WorkflowRepository,
|
WorkflowRepository,
|
||||||
WorkflowTasksRepository,
|
WorkflowTasksRepository,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const PluginRepo = this.db.getRepository<any>('applicationPlugins');
|
||||||
|
const pluginRecord = await PluginRepo.findOne({
|
||||||
|
filter: { name: this.name },
|
||||||
|
});
|
||||||
|
this.snowflake = new Snowflake({
|
||||||
|
custom_epoch: pluginRecord?.createdAt.getTime(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -56,15 +56,9 @@ export default class Processor {
|
|||||||
*/
|
*/
|
||||||
nodesMap = new Map<number, FlowNodeModel>();
|
nodesMap = new Map<number, FlowNodeModel>();
|
||||||
|
|
||||||
/**
|
private jobsMapByNodeKey: { [key: string]: JobModel } = {};
|
||||||
* @experimental
|
private jobResultsMapByNodeKey: { [key: string]: any } = {};
|
||||||
*/
|
private jobsToSave: Map<string, JobModel> = new Map();
|
||||||
jobsMap = new Map<number, JobModel>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @experimental
|
|
||||||
*/
|
|
||||||
jobsMapByNodeKey: { [key: string]: any } = {};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @experimental
|
* @experimental
|
||||||
@ -100,10 +94,9 @@ export default class Processor {
|
|||||||
|
|
||||||
private makeJobs(jobs: Array<JobModel>) {
|
private makeJobs(jobs: Array<JobModel>) {
|
||||||
jobs.forEach((job) => {
|
jobs.forEach((job) => {
|
||||||
this.jobsMap.set(job.id, job);
|
|
||||||
|
|
||||||
const node = this.nodesMap.get(job.nodeId);
|
const node = this.nodesMap.get(job.nodeId);
|
||||||
this.jobsMapByNodeKey[node.key] = job.result;
|
this.jobsMapByNodeKey[node.key] = job;
|
||||||
|
this.jobResultsMapByNodeKey[node.key] = job.result;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,11 +185,11 @@ export default class Processor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!(job instanceof Model)) {
|
if (!(job instanceof Model)) {
|
||||||
job.upstreamId = prevJob instanceof Model ? prevJob.get('id') : null;
|
// job.upstreamId = prevJob instanceof Model ? prevJob.get('id') : null;
|
||||||
job.nodeId = node.id;
|
job.nodeId = node.id;
|
||||||
job.nodeKey = node.key;
|
job.nodeKey = node.key;
|
||||||
}
|
}
|
||||||
const savedJob = await this.saveJob(job);
|
const savedJob = this.saveJob(job);
|
||||||
|
|
||||||
this.logger.info(
|
this.logger.info(
|
||||||
`execution (${this.execution.id}) run instruction [${node.type}] for node (${node.id}) finished as status: ${savedJob.status}`,
|
`execution (${this.execution.id}) run instruction [${node.type}] for node (${node.id}) finished as status: ${savedJob.status}`,
|
||||||
@ -258,6 +251,27 @@ export default class Processor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async exit(s?: number) {
|
public async exit(s?: number) {
|
||||||
|
if (this.jobsToSave.size) {
|
||||||
|
const newJobs = [];
|
||||||
|
for (const job of this.jobsToSave.values()) {
|
||||||
|
if (job.isNewRecord) {
|
||||||
|
newJobs.push(job);
|
||||||
|
} else {
|
||||||
|
await job.save({ transaction: this.mainTransaction });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (newJobs.length) {
|
||||||
|
const JobsModel = this.options.plugin.db.getModel('jobs');
|
||||||
|
await JobsModel.bulkCreate(
|
||||||
|
newJobs.map((job) => job.toJSON()),
|
||||||
|
{ transaction: this.mainTransaction },
|
||||||
|
);
|
||||||
|
for (const job of newJobs) {
|
||||||
|
job.isNewRecord = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.jobsToSave.clear();
|
||||||
|
}
|
||||||
if (typeof s === 'number') {
|
if (typeof s === 'number') {
|
||||||
const status = (<typeof Processor>this.constructor).StatusMap[s] ?? Math.sign(s);
|
const status = (<typeof Processor>this.constructor).StatusMap[s] ?? Math.sign(s);
|
||||||
await this.execution.update({ status }, { transaction: this.mainTransaction });
|
await this.execution.update({ status }, { transaction: this.mainTransaction });
|
||||||
@ -269,33 +283,30 @@ export default class Processor {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(optimize)
|
|
||||||
/**
|
/**
|
||||||
* @experimental
|
* @experimental
|
||||||
*/
|
*/
|
||||||
async saveJob(payload: JobModel | Record<string, any>): Promise<JobModel> {
|
saveJob(payload: JobModel | Record<string, any>): JobModel {
|
||||||
const { database } = <typeof ExecutionModel>this.execution.constructor;
|
const { database } = <typeof ExecutionModel>this.execution.constructor;
|
||||||
const { mainTransaction: transaction } = this;
|
|
||||||
const { model } = database.getCollection('jobs');
|
const { model } = database.getCollection('jobs');
|
||||||
let job;
|
let job;
|
||||||
if (payload instanceof model) {
|
if (payload instanceof model) {
|
||||||
job = await payload.save({ transaction });
|
job = payload;
|
||||||
} else if (payload.id) {
|
job.set('updatedAt', new Date());
|
||||||
job = await model.findByPk(payload.id, { transaction });
|
|
||||||
await job.update(payload, { transaction });
|
|
||||||
} else {
|
} else {
|
||||||
job = await model.create(
|
job = model.build({
|
||||||
{
|
|
||||||
...payload,
|
...payload,
|
||||||
|
id: this.options.plugin.snowflake.getUniqueID().toString(),
|
||||||
|
createdAt: new Date(),
|
||||||
|
updatedAt: new Date(),
|
||||||
executionId: this.execution.id,
|
executionId: this.execution.id,
|
||||||
},
|
});
|
||||||
{ transaction },
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
this.jobsMap.set(job.id, job);
|
this.jobsToSave.set(job.id, job);
|
||||||
|
|
||||||
this.lastSavedJob = job;
|
this.lastSavedJob = job;
|
||||||
this.jobsMapByNodeKey[job.nodeKey] = job.result;
|
this.jobsMapByNodeKey[job.nodeKey] = job;
|
||||||
|
this.jobResultsMapByNodeKey[job.nodeKey] = job.result;
|
||||||
|
|
||||||
return job;
|
return job;
|
||||||
}
|
}
|
||||||
@ -357,32 +368,20 @@ export default class Processor {
|
|||||||
* @experimental
|
* @experimental
|
||||||
*/
|
*/
|
||||||
findBranchParentJob(job: JobModel, node: FlowNodeModel): JobModel | null {
|
findBranchParentJob(job: JobModel, node: FlowNodeModel): JobModel | null {
|
||||||
for (let j: JobModel | undefined = job; j; j = this.jobsMap.get(j.upstreamId)) {
|
return this.jobsMapByNodeKey[node.key];
|
||||||
if (j.nodeId === node.id) {
|
|
||||||
return j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @experimental
|
* @experimental
|
||||||
*/
|
*/
|
||||||
findBranchLastJob(node: FlowNodeModel, job: JobModel): JobModel | null {
|
findBranchLastJob(node: FlowNodeModel, job: JobModel): JobModel | null {
|
||||||
const allJobs = Array.from(this.jobsMap.values());
|
const allJobs = Object.values(this.jobsMapByNodeKey);
|
||||||
const branchJobs = [];
|
const branchJobs = [];
|
||||||
for (let n = this.findBranchEndNode(node); n && n !== node.upstream; n = n.upstream) {
|
for (let n = this.findBranchEndNode(node); n && n !== node.upstream; n = n.upstream) {
|
||||||
branchJobs.push(...allJobs.filter((item) => item.nodeId === n.id));
|
branchJobs.push(...allJobs.filter((item) => item.nodeId === n.id));
|
||||||
}
|
}
|
||||||
branchJobs.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
|
branchJobs.sort((a, b) => a.updatedAt.getTime() - b.updatedAt.getTime());
|
||||||
for (let i = branchJobs.length - 1; i >= 0; i -= 1) {
|
return branchJobs[branchJobs.length - 1] || null;
|
||||||
for (let j = branchJobs[i]; j && j.id !== job.id; j = this.jobsMap.get(j.upstreamId)) {
|
|
||||||
if (j.upstreamId === job.id) {
|
|
||||||
return branchJobs[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -403,13 +402,13 @@ export default class Processor {
|
|||||||
for (let n = includeSelfScope ? node : this.findBranchParentNode(node); n; n = this.findBranchParentNode(n)) {
|
for (let n = includeSelfScope ? node : this.findBranchParentNode(node); n; n = this.findBranchParentNode(n)) {
|
||||||
const instruction = this.options.plugin.instructions.get(n.type);
|
const instruction = this.options.plugin.instructions.get(n.type);
|
||||||
if (typeof instruction?.getScope === 'function') {
|
if (typeof instruction?.getScope === 'function') {
|
||||||
$scopes[n.id] = $scopes[n.key] = instruction.getScope(n, this.jobsMapByNodeKey[n.key], this);
|
$scopes[n.id] = $scopes[n.key] = instruction.getScope(n, this.jobResultsMapByNodeKey[n.key], this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
$context: this.execution.context,
|
$context: this.execution.context,
|
||||||
$jobsMapByNodeKey: this.jobsMapByNodeKey,
|
$jobsMapByNodeKey: this.jobResultsMapByNodeKey,
|
||||||
$system: systemFns,
|
$system: systemFns,
|
||||||
$scopes,
|
$scopes,
|
||||||
$env: this.options.plugin.app.environment.getVariables(),
|
$env: this.options.plugin.app.environment.getVariables(),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user