From 886100eeefd49bbe7542a5d466b61d0f1aa64002 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Fri, 9 Aug 2019 07:37:10 +0200 Subject: [PATCH] :zap: Improve workflow retry --- packages/cli/src/ActiveExecutions.ts | 3 ++- packages/cli/src/Interfaces.ts | 13 ++++++++++++- packages/cli/src/Server.ts | 14 ++++++++++---- packages/cli/src/WorkflowExecuteAdditionalData.ts | 11 ++++++----- packages/core/src/Interfaces.ts | 7 ------- packages/editor-ui/src/Interface.ts | 5 ++++- .../editor-ui/src/components/ExecutionsList.vue | 6 ++---- .../src/components/mixins/pushConnection.ts | 2 +- .../editor-ui/src/components/mixins/restApi.ts | 2 +- 9 files changed, 38 insertions(+), 25 deletions(-) diff --git a/packages/cli/src/ActiveExecutions.ts b/packages/cli/src/ActiveExecutions.ts index 4d4d70f67e..f3cfba16f2 100644 --- a/packages/cli/src/ActiveExecutions.ts +++ b/packages/cli/src/ActiveExecutions.ts @@ -4,10 +4,10 @@ import { import { createDeferredPromise, - IExecutionsCurrentSummary, } from 'n8n-core'; import { + IExecutionsCurrentSummary, IExecutingWorkflowData, IWorkflowExecutionDataProcess, } from '.'; @@ -131,6 +131,7 @@ export class ActiveExecutions { returnData.push( { id, + retryOf: data.executionData.retryOf as string | undefined, startedAt: data.startedAt, mode: data.executionData.executionMode, workflowId: data.executionData.workflowData.id! as string, diff --git a/packages/cli/src/Interfaces.ts b/packages/cli/src/Interfaces.ts index 3f5ed18d27..fea2828941 100644 --- a/packages/cli/src/Interfaces.ts +++ b/packages/cli/src/Interfaces.ts @@ -162,8 +162,8 @@ export interface IExecutionsStopData { export interface IExecutionsSummary { id?: string; // executionIdDb idActive?: string; // executionIdActive - mode: WorkflowExecuteMode; finished?: boolean; + mode: WorkflowExecuteMode; retryOf?: string; retrySuccessId?: string; startedAt: Date; @@ -172,6 +172,16 @@ export interface IExecutionsSummary { workflowName?: string; } + +export interface IExecutionsCurrentSummary { + id: string; + retryOf?: string; + startedAt: Date; + mode: WorkflowExecuteMode; + workflowId: string; +} + + export interface IExecutionDeleteFilter { deleteBefore?: Date; filters?: IDataObject; @@ -260,6 +270,7 @@ export interface IPushDataExecutionFinished { data: IRun; executionIdActive: string; executionIdDb?: string; + retryOf?: string; } export interface IPushDataExecutionStarted { diff --git a/packages/cli/src/Server.ts b/packages/cli/src/Server.ts index 2e737eafbc..60edd4d86c 100644 --- a/packages/cli/src/Server.ts +++ b/packages/cli/src/Server.ts @@ -828,7 +828,7 @@ class App { // Retries a failed execution - this.app.post('/rest/executions/:id/retry', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise => { + this.app.post('/rest/executions/:id/retry', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise => { // Get the data to execute const fullExecutionDataFlatted = await Db.collections.Execution!.findOne(req.params.id); @@ -859,7 +859,13 @@ class App { const workflowRunner = new WorkflowRunner(); const executionId = await workflowRunner.run(data); - return executionId; + const executionData = await this.activeExecutionsInstance.getPostExecutePromise(executionId); + + if (executionData === undefined) { + throw new Error('The retry did not start for an unknown reason.'); + } + + return !!executionData.finished; })); @@ -893,7 +899,6 @@ class App { // Returns all the currently working executions - // this.app.get('/rest/executions-current', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise => { this.app.get('/rest/executions-current', ResponseHelper.send(async (req: express.Request, res: express.Response): Promise => { const executingWorkflows = this.activeExecutionsInstance.getActiveExecutions(); @@ -912,7 +917,8 @@ class App { { idActive: data.id.toString(), workflowId: data.workflowId, - mode:data.mode, + mode: data.mode, + retryOf: data.retryOf, startedAt: new Date(data.startedAt), } ); diff --git a/packages/cli/src/WorkflowExecuteAdditionalData.ts b/packages/cli/src/WorkflowExecuteAdditionalData.ts index e3e942f3df..5ab89792e6 100644 --- a/packages/cli/src/WorkflowExecuteAdditionalData.ts +++ b/packages/cli/src/WorkflowExecuteAdditionalData.ts @@ -67,7 +67,7 @@ function executeErrorWorkflow(workflowData: IWorkflowBase, fullRunData: IRun, mo * @param {string} executionIdActive The id of the finished execution * @param {string} [executionIdDb] The database id of finished execution */ -export function pushExecutionFinished(fullRunData: IRun, executionIdActive: string, executionIdDb?: string) { +export function pushExecutionFinished(fullRunData: IRun, executionIdActive: string, executionIdDb?: string, retryOf?: string) { // Clone the object except the runData. That one is not supposed // to be send. Because that data got send piece by piece after // each node which finished executing @@ -87,6 +87,7 @@ export function pushExecutionFinished(fullRunData: IRun, executionIdActive: stri executionIdActive, executionIdDb, data: pushRunData, + retryOf, }; pushInstance.send('executionFinished', sendData); @@ -166,7 +167,7 @@ const hooks = (mode: WorkflowExecuteMode, workflowData: IWorkflowBase, execution } if (mode === 'manual' && saveManualExecutions === false) { - pushExecutionFinished(fullRunData, executionId); + pushExecutionFinished(fullRunData, executionId, undefined, retryOf); executeErrorWorkflow(workflowData, fullRunData, mode); return; } @@ -183,7 +184,7 @@ const hooks = (mode: WorkflowExecuteMode, workflowData: IWorkflowBase, execution if (workflowDidSucceed === true && saveDataSuccessExecution === 'none' || workflowDidSucceed === false && saveDataErrorExecution === 'none' ) { - pushExecutionFinished(fullRunData, executionId); + pushExecutionFinished(fullRunData, executionId, undefined, retryOf); executeErrorWorkflow(workflowData, fullRunData, mode); return; } @@ -216,10 +217,10 @@ const hooks = (mode: WorkflowExecuteMode, workflowData: IWorkflowBase, execution await Db.collections.Execution!.update(retryOf, { retrySuccessId: executionResult.id }); } - pushExecutionFinished(fullRunData, executionId, executionResult.id as string); + pushExecutionFinished(fullRunData, executionId, executionResult.id as string, retryOf); executeErrorWorkflow(workflowData, fullRunData, mode, executionResult ? executionResult.id as string : undefined); } catch (error) { - pushExecutionFinished(fullRunData, executionId); + pushExecutionFinished(fullRunData, executionId, undefined, retryOf); executeErrorWorkflow(workflowData, fullRunData, mode); } }, diff --git a/packages/core/src/Interfaces.ts b/packages/core/src/Interfaces.ts index 22fc156130..1b5274ee6f 100644 --- a/packages/core/src/Interfaces.ts +++ b/packages/core/src/Interfaces.ts @@ -46,13 +46,6 @@ export interface IExecuteSingleFunctions extends IExecuteSingleFunctionsBase { } -export interface IExecutionsCurrentSummary { - id: string; - startedAt: Date; - mode: WorkflowExecuteMode; - workflowId: string; -} - export interface ITriggerFunctions extends ITriggerFunctionsBase { helpers: { prepareBinaryData(binaryData: Buffer, filePath?: string, mimeType?: string): Promise; diff --git a/packages/editor-ui/src/Interface.ts b/packages/editor-ui/src/Interface.ts index c115675e24..3e7cc8ebc9 100644 --- a/packages/editor-ui/src/Interface.ts +++ b/packages/editor-ui/src/Interface.ts @@ -143,7 +143,7 @@ export interface IRestApi { getCredentialTypes(): Promise; getExecution(id: string): Promise; deleteExecutions(sendData: IExecutionDeleteFilter): Promise; - retryExecution(id: string): Promise; + retryExecution(id: string): Promise; getTimezones(): Promise; } @@ -303,6 +303,8 @@ export interface IExecutionsCurrentSummaryExtended { idActive: string; finished?: boolean; mode: WorkflowExecuteMode; + retryOf?: string; + retrySuccessId?: string; startedAt: Date; stoppedAt?: Date; workflowId: string; @@ -356,6 +358,7 @@ export interface IPushDataExecutionFinished { data: IRun; executionIdActive: string; executionIdDb?: string; + retryOf?: string; } export interface IPushDataExecutionStarted { diff --git a/packages/editor-ui/src/components/ExecutionsList.vue b/packages/editor-ui/src/components/ExecutionsList.vue index c59cedda8c..dd2b0648d2 100644 --- a/packages/editor-ui/src/components/ExecutionsList.vue +++ b/packages/editor-ui/src/components/ExecutionsList.vue @@ -390,9 +390,9 @@ export default mixins( this.isDataLoading = true; try { - const data = await this.restApi().retryExecution(execution.id); + const retrySuccessful = await this.restApi().retryExecution(execution.id); - if (data.finished === true) { + if (retrySuccessful === true) { this.$showMessage({ title: 'Retry successful', message: 'The retry was successful!', @@ -406,13 +406,11 @@ export default mixins( }); } - this.refreshData(); this.isDataLoading = false; } catch (error) { this.$showError(error, 'Problem with retry', 'There was a problem with the retry:'); this.isDataLoading = false; - this.refreshData(); } }, async refreshData () { diff --git a/packages/editor-ui/src/components/mixins/pushConnection.ts b/packages/editor-ui/src/components/mixins/pushConnection.ts index bdf7014cf3..eb4c8fd868 100644 --- a/packages/editor-ui/src/components/mixins/pushConnection.ts +++ b/packages/editor-ui/src/components/mixins/pushConnection.ts @@ -160,7 +160,6 @@ export const pushConnection = mixins( const runDataExecuted = pushData.data; - if (runDataExecuted.finished !== true) { // There was a problem with executing the workflow let errorMessage = 'There was a problem executing the workflow!'; @@ -202,6 +201,7 @@ export const pushConnection = mixins( finished: false, mode: pushData.mode, startedAt: pushData.startedAt, + retryOf: pushData.retryOf, workflowId: pushData.workflowId, workflowName: pushData.workflowName, }; diff --git a/packages/editor-ui/src/components/mixins/restApi.ts b/packages/editor-ui/src/components/mixins/restApi.ts index 3702e950ed..667f7cae8a 100644 --- a/packages/editor-ui/src/components/mixins/restApi.ts +++ b/packages/editor-ui/src/components/mixins/restApi.ts @@ -263,7 +263,7 @@ export const restApi = Vue.extend({ }, // Returns the execution with the given name - retryExecution: (id: string): Promise => { + retryExecution: (id: string): Promise => { return self.restApi().makeRestApiRequest('POST', `/executions/${id}/retry`); },