Run workflows in own independent subprocess

This commit is contained in:
Jan Oberhauser
2019-08-08 20:38:25 +02:00
parent abb0a52b08
commit d59a043e3f
21 changed files with 926 additions and 369 deletions

View File

@@ -106,6 +106,31 @@ export interface IDataObject {
}
export interface IGetExecuteTriggerFunctions {
(workflow: Workflow, node: INode, additionalData: IWorkflowExecuteAdditionalData, mode: WorkflowExecuteMode): ITriggerFunctions;
}
export interface IGetExecuteFunctions {
(workflow: Workflow, runExecutionData: IRunExecutionData, runIndex: number, connectionInputData: INodeExecutionData[], inputData: ITaskDataConnections, node: INode, additionalData: IWorkflowExecuteAdditionalData, mode: WorkflowExecuteMode): IExecuteFunctions;
}
export interface IGetExecuteSingleFunctions {
(workflow: Workflow, runExecutionData: IRunExecutionData, runIndex: number, connectionInputData: INodeExecutionData[], inputData: ITaskDataConnections, node: INode, itemIndex: number, additionalData: IWorkflowExecuteAdditionalData, mode: WorkflowExecuteMode): IExecuteSingleFunctions;
}
export interface IGetExecuteHookFunctions {
(workflow: Workflow, node: INode, additionalData: IWorkflowExecuteAdditionalData, mode: WorkflowExecuteMode, isTest?: boolean, webhookData?: IWebhookData): IHookFunctions;
}
export interface IGetExecuteWebhookFunctions {
(workflow: Workflow, node: INode, additionalData: IWorkflowExecuteAdditionalData, mode: WorkflowExecuteMode, webhookData: IWebhookData): IWebhookFunctions;
}
export interface IExecuteData {
data: ITaskDataConnections;
node: INode;
@@ -250,11 +275,11 @@ export interface INodeExecutionData {
export interface INodeExecuteFunctions {
getExecuteTriggerFunctions(workflow: Workflow, node: INode, additionalData: IWorkflowExecuteAdditionalData, mode: WorkflowExecuteMode): ITriggerFunctions;
getExecuteFunctions(workflow: Workflow, runExecutionData: IRunExecutionData, runIndex: number, connectionInputData: INodeExecutionData[], inputData: ITaskDataConnections, node: INode, additionalData: IWorkflowExecuteAdditionalData, mode: WorkflowExecuteMode): IExecuteFunctions;
getExecuteSingleFunctions(workflow: Workflow, runExecutionData: IRunExecutionData, runIndex: number, connectionInputData: INodeExecutionData[], inputData: ITaskDataConnections, node: INode, itemIndex: number, additionalData: IWorkflowExecuteAdditionalData, mode: WorkflowExecuteMode): IExecuteSingleFunctions;
getExecuteHookFunctions(workflow: Workflow, node: INode, additionalData: IWorkflowExecuteAdditionalData, mode: WorkflowExecuteMode, isTest?: boolean, webhookData?: IWebhookData): IHookFunctions;
getExecuteWebhookFunctions(workflow: Workflow, node: INode, additionalData: IWorkflowExecuteAdditionalData, mode: WorkflowExecuteMode, webhookData: IWebhookData): IWebhookFunctions;
getExecuteTriggerFunctions: IGetExecuteTriggerFunctions;
getExecuteFunctions: IGetExecuteFunctions;
getExecuteSingleFunctions: IGetExecuteSingleFunctions;
getExecuteHookFunctions: IGetExecuteHookFunctions;
getExecuteWebhookFunctions: IGetExecuteWebhookFunctions;
}
@@ -452,17 +477,21 @@ export interface IWebhookResonseData {
export type WebhookResponseData = 'allEntries' | 'firstEntryJson' | 'firstEntryBinary';
export type WebhookResponseMode = 'onReceived' | 'lastNode';
export interface INodeTypesObject {
[key: string]: INodeType;
}
export interface INodeTypes {
init(nodeTypes?: INodeTypesObject): Promise<void>;
nodeTypes: INodeTypeData;
init(nodeTypes?: INodeTypeData): Promise<void>;
getAll(): INodeType[];
getByName(nodeType: string): INodeType | undefined;
}
export interface INodeTypeData {
[key: string]: {
type: INodeType;
sourcePath: string;
};
}
export interface IRun {
data: IRunExecutionData;
finished?: boolean;
@@ -537,19 +566,17 @@ export interface IWorkflowCredentials {
}
export interface IWorkflowExecuteHooks {
afterExecute? (data: IRun, waitingExecutionData: IWaitingForExecution): Promise<void>;
[key: string]: Array<((...args: any[]) => Promise<void>)> | undefined; // tslint:disable-line:no-any
nodeExecuteAfter?: Array<((nodeName: string, data: ITaskData) => Promise<void>)>;
nodeExecuteBefore?: Array<((nodeName: string) => Promise<void>)>;
workflowExecuteAfter?: Array<((data: IRun, newStaticData: IDataObject) => Promise<void>)>;
workflowExecuteBefore?: Array<(() => Promise<void>)>;
}
export interface IWorkflowExecuteAdditionalData {
credentials: IWorkflowCredentials;
encryptionKey: string;
hooks?: {
[key: string]: Array<((...args: any[]) => Promise<void>)> | undefined; // tslint:disable-line:no-any
nodeExecuteAfter?: Array<((executionId: string, nodeName: string, data: ITaskData) => Promise<void>)>;
nodeExecuteBefore?: Array<((nodeName: string, executionId: string) => Promise<void>)>;
workflowExecuteAfter?: Array<((data: IRun, executionId: string) => Promise<void>)>;
workflowExecuteBefore?: Array<((executionId: string) => Promise<void>)>;
};
hooks?: IWorkflowExecuteHooks;
httpResponse?: express.Response;
httpRequest?: express.Request;
timezone: string;

View File

@@ -1,6 +1,7 @@
import {
IConnections,
IGetExecuteTriggerFunctions,
INode,
NodeHelpers,
INodes,
@@ -954,14 +955,14 @@ export class Workflow {
* when the node has data.
*
* @param {INode} node
* @param {INodeExecuteFunctions} nodeExecuteFunctions
* @param {IGetExecuteTriggerFunctions} getTriggerFunctions
* @param {IWorkflowExecuteAdditionalData} additionalData
* @param {WorkflowExecuteMode} mode
* @returns {(Promise<ITriggerResponse | undefined>)}
* @memberof Workflow
*/
async runTrigger(node: INode, nodeExecuteFunctions: INodeExecuteFunctions, additionalData: IWorkflowExecuteAdditionalData, mode: WorkflowExecuteMode): Promise<ITriggerResponse | undefined> {
const thisArgs = nodeExecuteFunctions.getExecuteTriggerFunctions(this, node, additionalData, mode);
async runTrigger(node: INode, getTriggerFunctions: IGetExecuteTriggerFunctions, additionalData: IWorkflowExecuteAdditionalData, mode: WorkflowExecuteMode): Promise<ITriggerResponse | undefined> {
const triggerFunctions = getTriggerFunctions(this, node, additionalData, mode);
const nodeType = this.nodeTypes.getByName(node.type);
@@ -976,11 +977,11 @@ export class Workflow {
if (mode === 'manual') {
// In manual mode we do not just start the trigger function we also
// want to be able to get informed as soon as the first data got emitted
const triggerReponse = await nodeType.trigger!.call(thisArgs);
const triggerReponse = await nodeType.trigger!.call(triggerFunctions);
// Add the manual trigger response which resolves when the first time data got emitted
triggerReponse!.manualTriggerResponse = new Promise((resolve) => {
thisArgs.emit = ((resolve) => (data: INodeExecutionData[][]) => {
triggerFunctions.emit = ((resolve) => (data: INodeExecutionData[][]) => {
resolve(data);
})(resolve);
});
@@ -988,7 +989,7 @@ export class Workflow {
return triggerReponse;
} else {
// In all other modes simply start the trigger
return nodeType.trigger!.call(thisArgs);
return nodeType.trigger!.call(triggerFunctions);
}
}
@@ -1089,7 +1090,7 @@ export class Workflow {
} else if (nodeType.trigger) {
if (mode === 'manual') {
// In manual mode start the trigger
const triggerResponse = await this.runTrigger(node, nodeExecuteFunctions, additionalData, mode);
const triggerResponse = await this.runTrigger(node, nodeExecuteFunctions.getExecuteTriggerFunctions, additionalData, mode);
if (triggerResponse === undefined) {
return null;