From b7dfa0d3add76dd934a99f40805114d8ce762ed0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E0=A4=95=E0=A4=BE=E0=A4=B0=E0=A4=A4=E0=A5=8B=E0=A4=AB?=
 =?UTF-8?q?=E0=A5=8D=E0=A4=AB=E0=A5=87=E0=A4=B2=E0=A4=B8=E0=A5=8D=E0=A4=95?=
 =?UTF-8?q?=E0=A5=8D=E0=A4=B0=E0=A4=BF=E0=A4=AA=E0=A5=8D=E0=A4=9F=E2=84=A2?=
 <aditya@netroy.in>
Date: Fri, 24 Nov 2023 12:06:25 +0100
Subject: [PATCH] handle cancel correctly

---
 packages/cli/src/ActiveExecutions.ts          |  5 +++--
 packages/core/src/WorkflowExecute.ts          | 22 ++++++-------------
 .../editor-ui/src/mixins/pushConnection.ts    | 20 +++++++++++++----
 packages/editor-ui/src/views/NodeView.vue     |  4 ----
 4 files changed, 26 insertions(+), 25 deletions(-)

diff --git a/packages/cli/src/ActiveExecutions.ts b/packages/cli/src/ActiveExecutions.ts
index 3835c02bd2960..c4a03efc6c663 100644
--- a/packages/cli/src/ActiveExecutions.ts
+++ b/packages/cli/src/ActiveExecutions.ts
@@ -162,6 +162,8 @@ export class ActiveExecutions {
 			return;
 		}
 
+		const postExecutePromise = this.getPostExecutePromise(executionId);
+
 		// In case something goes wrong make sure that promise gets first
 		// returned that it gets then also resolved correctly.
 		if (this.activeExecutions[executionId].process !== undefined) {
@@ -177,10 +179,9 @@ export class ActiveExecutions {
 		} else {
 			// Workflow is running in current process
 			this.activeExecutions[executionId].workflowExecution!.cancel();
-			setTimeout(() => this.remove(executionId), 10);
 		}
 
-		return this.getPostExecutePromise(executionId);
+		return postExecutePromise;
 	}
 
 	/**
diff --git a/packages/core/src/WorkflowExecute.ts b/packages/core/src/WorkflowExecute.ts
index ea67ffb169cff..0822848f522c4 100644
--- a/packages/core/src/WorkflowExecute.ts
+++ b/packages/core/src/WorkflowExecute.ts
@@ -820,21 +820,16 @@ export class WorkflowExecute {
 		let closeFunction: Promise<void> | undefined;
 
 		return new PCancelable(async (resolve, reject, onCancel) => {
-			let gotCancel = false;
-
 			// Let as many nodes listen to the abort signal, without getting the MaxListenersExceededWarning
 			setMaxListeners(Infinity, this.abortController.signal);
 
 			onCancel.shouldReject = false;
 			onCancel(() => {
-				gotCancel = true;
+				this.status = 'canceled';
 				this.abortController.abort();
-				void this.processSuccessExecution(
-					startedAt,
-					workflow,
-					new WorkflowOperationError('Workflow has been canceled!'),
-					closeFunction,
-				);
+				const fullRunData = this.getFullRunData(startedAt);
+				void this.executeHook('workflowExecuteAfter', [fullRunData]);
+				setTimeout(() => resolve(fullRunData), 10);
 			});
 
 			const returnPromise = (async () => {
@@ -881,10 +876,10 @@ export class WorkflowExecute {
 						this.additionalData.executionTimeoutTimestamp !== undefined &&
 						Date.now() >= this.additionalData.executionTimeoutTimestamp
 					) {
-						gotCancel = true;
+						this.status = 'canceled';
 					}
 
-					if (gotCancel) {
+					if (this.status === 'canceled') {
 						return;
 					}
 
@@ -1014,9 +1009,6 @@ export class WorkflowExecute {
 					}
 
 					for (let tryIndex = 0; tryIndex < maxTries; tryIndex++) {
-						if (gotCancel) {
-							return;
-						}
 						try {
 							if (tryIndex !== 0) {
 								// Reset executionError from previous error try
@@ -1646,7 +1638,7 @@ export class WorkflowExecute {
 				return;
 			})()
 				.then(async () => {
-					if (gotCancel && executionError === undefined) {
+					if (this.status === 'canceled' && executionError === undefined) {
 						return this.processSuccessExecution(
 							startedAt,
 							workflow,
diff --git a/packages/editor-ui/src/mixins/pushConnection.ts b/packages/editor-ui/src/mixins/pushConnection.ts
index eda1d1d810a03..6a375e9b96115 100644
--- a/packages/editor-ui/src/mixins/pushConnection.ts
+++ b/packages/editor-ui/src/mixins/pushConnection.ts
@@ -272,7 +272,8 @@ export const pushConnection = defineComponent({
 					return false;
 				}
 
-				if (this.workflowsStore.activeExecutionId !== pushData.executionId) {
+				const { activeExecutionId } = this.workflowsStore;
+				if (activeExecutionId !== pushData.executionId) {
 					// The workflow which did finish execution did either not get started
 					// by this session or we do not have the execution id yet.
 					if (isRetry !== true) {
@@ -285,10 +286,17 @@ export const pushConnection = defineComponent({
 
 				let runDataExecutedErrorMessage = this.getExecutionError(runDataExecuted.data);
 
-				if (pushData.data.status === 'crashed') {
+				if (runDataExecuted.status === 'crashed') {
 					runDataExecutedErrorMessage = this.$locale.baseText(
 						'pushConnection.executionFailed.message',
 					);
+				} else if (runDataExecuted.status === 'canceled') {
+					runDataExecutedErrorMessage = this.$locale.baseText(
+						'executionsList.showMessage.stopExecution.message',
+						{
+							interpolate: { activeExecutionId },
+						},
+					);
 				}
 
 				const lineNumber = runDataExecuted?.data?.resultData?.error?.lineNumber;
@@ -389,7 +397,11 @@ export const pushConnection = defineComponent({
 						});
 					} else {
 						let title: string;
-						if (runDataExecuted.data.resultData.lastNodeExecuted) {
+						let type = 'error';
+						if (runDataExecuted.status === 'canceled') {
+							title = this.$locale.baseText('nodeView.showMessage.stopExecutionTry.title');
+							type = 'warning';
+						} else if (runDataExecuted.data.resultData.lastNodeExecuted) {
 							title = `Problem in node ‘${runDataExecuted.data.resultData.lastNodeExecuted}‘`;
 						} else {
 							title = 'Problem executing workflow';
@@ -398,7 +410,7 @@ export const pushConnection = defineComponent({
 						this.showMessage({
 							title,
 							message: runDataExecutedErrorMessage,
-							type: 'error',
+							type,
 							duration: 0,
 							dangerouslyUseHTMLString: true,
 						});
diff --git a/packages/editor-ui/src/views/NodeView.vue b/packages/editor-ui/src/views/NodeView.vue
index 705780fac7550..94c3c0317e38a 100644
--- a/packages/editor-ui/src/views/NodeView.vue
+++ b/packages/editor-ui/src/views/NodeView.vue
@@ -1562,10 +1562,6 @@ export default defineComponent({
 			try {
 				this.stopExecutionInProgress = true;
 				await this.workflowsStore.stopCurrentExecution(executionId);
-				this.showMessage({
-					title: this.$locale.baseText('nodeView.showMessage.stopExecutionTry.title'),
-					type: 'success',
-				});
 			} catch (error) {
 				// Execution stop might fail when the execution has already finished. Let's treat this here.
 				const execution = await this.workflowsStore.getExecution(executionId);