feat(core): Add closeFunction support to Sub-Nodes (#7708)

Github issue / Community forum post (link here to close automatically):

---------

Signed-off-by: Oleg Ivaniv <me@olegivaniv.com>
Co-authored-by: Oleg Ivaniv <me@olegivaniv.com>
This commit is contained in:
Jan Oberhauser
2023-12-21 14:21:09 +01:00
committed by GitHub
parent 9ac8825a67
commit bec0faed9e
6 changed files with 47 additions and 6 deletions

View File

@@ -377,6 +377,8 @@ export interface IConnections {
export type GenericValue = string | object | number | boolean | undefined | null;
export type CloseFunction = () => Promise<void>;
export interface IDataObject {
[key: string]: GenericValue | IDataObject | GenericValue[] | IDataObject[];
}
@@ -410,7 +412,7 @@ export interface IGetExecuteTriggerFunctions {
export interface IRunNodeResponse {
data: INodeExecutionData[][] | null | undefined;
closeFunction?: () => Promise<void>;
closeFunction?: CloseFunction;
}
export interface IGetExecuteFunctions {
(
@@ -423,6 +425,7 @@ export interface IGetExecuteFunctions {
additionalData: IWorkflowExecuteAdditionalData,
executeData: IExecuteData,
mode: WorkflowExecuteMode,
closeFunctions: CloseFunction[],
abortSignal?: AbortSignal,
): IExecuteFunctions;
}
@@ -1289,13 +1292,13 @@ export type IParameterLabel = {
};
export interface IPollResponse {
closeFunction?: () => Promise<void>;
closeFunction?: CloseFunction;
}
export interface ITriggerResponse {
closeFunction?: () => Promise<void>;
closeFunction?: CloseFunction;
// To manually trigger the run
manualTriggerFunction?: () => Promise<void>;
manualTriggerFunction?: CloseFunction;
// Gets added automatically at manual workflow runs resolves with
// the first emitted data
manualTriggerResponse?: Promise<INodeExecutionData[][]>;
@@ -1324,6 +1327,7 @@ export namespace MultiPartFormData {
export interface SupplyData {
metadata?: IDataObject;
response: unknown;
closeFunction?: CloseFunction;
}
export interface INodeType {

View File

@@ -37,6 +37,7 @@ import type {
NodeParameterValueType,
PostReceiveAction,
JsonObject,
CloseFunction,
} from './Interfaces';
import * as NodeHelpers from './NodeHelpers';
@@ -94,6 +95,7 @@ export class RoutingNode {
if (nodeType.description.credentials?.length) {
credentialType = nodeType.description.credentials[0].name;
}
const closeFunctions: CloseFunction[] = [];
const executeFunctions = nodeExecuteFunctions.getExecuteFunctions(
this.workflow,
this.runExecutionData,
@@ -104,6 +106,7 @@ export class RoutingNode {
this.additionalData,
executeData,
this.mode,
closeFunctions,
abortSignal,
);

View File

@@ -42,6 +42,7 @@ import type {
IRunNodeResponse,
NodeParameterValueType,
ConnectionTypes,
CloseFunction,
} from './Interfaces';
import { Node } from './Interfaces';
import type { IDeferredPromise } from './DeferredPromise';
@@ -1298,6 +1299,7 @@ export class Workflow {
}
if (nodeType.execute) {
const closeFunctions: CloseFunction[] = [];
const context = nodeExecuteFunctions.getExecuteFunctions(
this,
runExecutionData,
@@ -1308,12 +1310,31 @@ export class Workflow {
additionalData,
executionData,
mode,
closeFunctions,
abortSignal,
);
const data =
nodeType instanceof Node
? await nodeType.execute(context)
: await nodeType.execute.call(context);
const closeFunctionsResults = await Promise.allSettled(
closeFunctions.map(async (fn) => fn()),
);
const closingErrors = closeFunctionsResults
.filter((result): result is PromiseRejectedResult => result.status === 'rejected')
.map((result) => result.reason);
if (closingErrors.length > 0) {
if (closingErrors[0] instanceof Error) throw closingErrors[0];
throw new ApplicationError("Error on execution node's close function(s)", {
extra: { nodeName: node.name },
tags: { nodeType: node.type },
cause: closingErrors,
});
}
return { data };
} else if (nodeType.poll) {
if (mode === 'manual') {