From 03a78a423f2517169174c0dffd285ac8dbc98687 Mon Sep 17 00:00:00 2001 From: richardwang98 Date: Mon, 27 Mar 2023 11:48:28 -0400 Subject: [PATCH] code clean --- ...WorkStatus.java => ParodosWorkStatus.java} | 4 +- .../task/enums/WorkFlowTaskStatus.java | 2 +- workflow-service-sdk/api/openapi.yaml | 2 + .../docs/WorkFlowCheckerTaskRequestDTO.md | 1 + .../docs/WorkStatusResponseDTO.md | 1 + .../model/WorkFlowCheckerTaskRequestDTO.java | 4 +- .../sdk/model/WorkStatusResponseDTO.java | 4 +- .../generated/openapi/openapi.json | 4 +- .../WorkflowExecutionNotFoundException.java | 34 +++ .../WorkflowPersistenceFailedException.java | 34 +++ .../aspect/WorkFlowExecutionAspect.java | 249 ++++++++++-------- .../aspect/WorkFlowTaskExecutionAspect.java | 117 ++++---- .../execution/dto/WorkStatusResponseDTO.java | 4 +- .../execution/service/WorkFlowService.java | 2 +- .../service/WorkFlowServiceDelegate.java | 20 +- .../service/WorkFlowServiceImpl.java | 39 ++- .../aspect/WorkFlowExecutionAspectTest.java | 48 ++-- .../WorkFlowTaskExecutionAspectTest.java | 4 +- .../controller/WorkFlowControllerTest.java | 17 +- .../service/WorkFlowServiceDelegateTest.java | 8 +- .../service/WorkFlowServiceImplTest.java | 14 +- 21 files changed, 366 insertions(+), 246 deletions(-) rename parodos-model-api/src/main/java/com/redhat/parodos/workflow/enums/{WorkStatus.java => ParodosWorkStatus.java} (92%) create mode 100644 workflow-service/src/main/java/com/redhat/parodos/workflow/exceptions/WorkflowExecutionNotFoundException.java create mode 100644 workflow-service/src/main/java/com/redhat/parodos/workflow/exceptions/WorkflowPersistenceFailedException.java diff --git a/parodos-model-api/src/main/java/com/redhat/parodos/workflow/enums/WorkStatus.java b/parodos-model-api/src/main/java/com/redhat/parodos/workflow/enums/ParodosWorkStatus.java similarity index 92% rename from parodos-model-api/src/main/java/com/redhat/parodos/workflow/enums/WorkStatus.java rename to parodos-model-api/src/main/java/com/redhat/parodos/workflow/enums/ParodosWorkStatus.java index 7c10b4569..4820c8c2d 100644 --- a/parodos-model-api/src/main/java/com/redhat/parodos/workflow/enums/WorkStatus.java +++ b/parodos-model-api/src/main/java/com/redhat/parodos/workflow/enums/ParodosWorkStatus.java @@ -22,8 +22,8 @@ * @author Richard Wang (Github: richardw98) * @author Annel Ketcha (Github: anludke) */ -public enum WorkStatus { +public enum ParodosWorkStatus { - FAILED, COMPLETED, PENDING + FAILED, COMPLETED, PENDING, IN_PROGRESS } diff --git a/parodos-model-api/src/main/java/com/redhat/parodos/workflow/task/enums/WorkFlowTaskStatus.java b/parodos-model-api/src/main/java/com/redhat/parodos/workflow/task/enums/WorkFlowTaskStatus.java index f65932274..b61658faa 100644 --- a/parodos-model-api/src/main/java/com/redhat/parodos/workflow/task/enums/WorkFlowTaskStatus.java +++ b/parodos-model-api/src/main/java/com/redhat/parodos/workflow/task/enums/WorkFlowTaskStatus.java @@ -24,6 +24,6 @@ */ public enum WorkFlowTaskStatus { - FAILED, COMPLETED, IN_PROGRESS + FAILED, COMPLETED, IN_PROGRESS, PENDING } diff --git a/workflow-service-sdk/api/openapi.yaml b/workflow-service-sdk/api/openapi.yaml index aab602166..2170b4e05 100644 --- a/workflow-service-sdk/api/openapi.yaml +++ b/workflow-service-sdk/api/openapi.yaml @@ -334,6 +334,7 @@ components: - FAILED - COMPLETED - IN_PROGRESS + - PENDING type: string type: object WorkFlowDefinitionResponseDTO: @@ -735,6 +736,7 @@ components: - FAILED - COMPLETED - PENDING + - IN_PROGRESS type: string type: enum: diff --git a/workflow-service-sdk/docs/WorkFlowCheckerTaskRequestDTO.md b/workflow-service-sdk/docs/WorkFlowCheckerTaskRequestDTO.md index 843a578c5..2f109a415 100644 --- a/workflow-service-sdk/docs/WorkFlowCheckerTaskRequestDTO.md +++ b/workflow-service-sdk/docs/WorkFlowCheckerTaskRequestDTO.md @@ -18,6 +18,7 @@ Name | Value FAILED | "FAILED" COMPLETED | "COMPLETED" IN_PROGRESS | "IN_PROGRESS" +PENDING | "PENDING" diff --git a/workflow-service-sdk/docs/WorkStatusResponseDTO.md b/workflow-service-sdk/docs/WorkStatusResponseDTO.md index e9a6bc7dd..78d10ba73 100644 --- a/workflow-service-sdk/docs/WorkStatusResponseDTO.md +++ b/workflow-service-sdk/docs/WorkStatusResponseDTO.md @@ -20,6 +20,7 @@ Name | Value FAILED | "FAILED" COMPLETED | "COMPLETED" PENDING | "PENDING" +IN_PROGRESS | "IN_PROGRESS" diff --git a/workflow-service-sdk/src/main/java/com/redhat/parodos/sdk/model/WorkFlowCheckerTaskRequestDTO.java b/workflow-service-sdk/src/main/java/com/redhat/parodos/sdk/model/WorkFlowCheckerTaskRequestDTO.java index e7396ad83..e876aa4a8 100644 --- a/workflow-service-sdk/src/main/java/com/redhat/parodos/sdk/model/WorkFlowCheckerTaskRequestDTO.java +++ b/workflow-service-sdk/src/main/java/com/redhat/parodos/sdk/model/WorkFlowCheckerTaskRequestDTO.java @@ -38,7 +38,9 @@ public enum StatusEnum { COMPLETED("COMPLETED"), - IN_PROGRESS("IN_PROGRESS"); + IN_PROGRESS("IN_PROGRESS"), + + PENDING("PENDING"); private String value; diff --git a/workflow-service-sdk/src/main/java/com/redhat/parodos/sdk/model/WorkStatusResponseDTO.java b/workflow-service-sdk/src/main/java/com/redhat/parodos/sdk/model/WorkStatusResponseDTO.java index 1ea864b91..080109e15 100644 --- a/workflow-service-sdk/src/main/java/com/redhat/parodos/sdk/model/WorkStatusResponseDTO.java +++ b/workflow-service-sdk/src/main/java/com/redhat/parodos/sdk/model/WorkStatusResponseDTO.java @@ -42,7 +42,9 @@ public enum StatusEnum { COMPLETED("COMPLETED"), - PENDING("PENDING"); + PENDING("PENDING"), + + IN_PROGRESS("IN_PROGRESS"); private String value; diff --git a/workflow-service/generated/openapi/openapi.json b/workflow-service/generated/openapi/openapi.json index 6e96d09d9..853037259 100644 --- a/workflow-service/generated/openapi/openapi.json +++ b/workflow-service/generated/openapi/openapi.json @@ -398,7 +398,7 @@ "properties" : { "status" : { "type" : "string", - "enum" : [ "FAILED", "COMPLETED", "IN_PROGRESS" ] + "enum" : [ "FAILED", "COMPLETED", "IN_PROGRESS", "PENDING" ] } } }, @@ -593,7 +593,7 @@ }, "status" : { "type" : "string", - "enum" : [ "FAILED", "COMPLETED", "PENDING" ] + "enum" : [ "FAILED", "COMPLETED", "PENDING", "IN_PROGRESS" ] }, "type" : { "type" : "string", diff --git a/workflow-service/src/main/java/com/redhat/parodos/workflow/exceptions/WorkflowExecutionNotFoundException.java b/workflow-service/src/main/java/com/redhat/parodos/workflow/exceptions/WorkflowExecutionNotFoundException.java new file mode 100644 index 000000000..9586b7faf --- /dev/null +++ b/workflow-service/src/main/java/com/redhat/parodos/workflow/exceptions/WorkflowExecutionNotFoundException.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2022 Red Hat Developer + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.redhat.parodos.workflow.exceptions; + +/** + * The WorkflowExecutionNotFoundException wraps unchecked standard Java exception and + * enriches them with a custom error code. You can use this exception when a Workflow + * Execution is not Found. + * + * @author Richard Wang (Github: richardW98) + */ + +public class WorkflowExecutionNotFoundException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + public WorkflowExecutionNotFoundException(String message) { + super(message); + } + +} diff --git a/workflow-service/src/main/java/com/redhat/parodos/workflow/exceptions/WorkflowPersistenceFailedException.java b/workflow-service/src/main/java/com/redhat/parodos/workflow/exceptions/WorkflowPersistenceFailedException.java new file mode 100644 index 000000000..cf779cd95 --- /dev/null +++ b/workflow-service/src/main/java/com/redhat/parodos/workflow/exceptions/WorkflowPersistenceFailedException.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2022 Red Hat Developer + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.redhat.parodos.workflow.exceptions; + +/** + * The WorkflowPersistenceFailedException wraps unchecked standard Java exception and + * enriches them with a custom error code. You can use this exception when a Database + * Operation is not Failed. + * + * @author Richard Wang (Github: richardW98) + */ + +public class WorkflowPersistenceFailedException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + public WorkflowPersistenceFailedException(String message) { + super(message); + } + +} diff --git a/workflow-service/src/main/java/com/redhat/parodos/workflow/execution/aspect/WorkFlowExecutionAspect.java b/workflow-service/src/main/java/com/redhat/parodos/workflow/execution/aspect/WorkFlowExecutionAspect.java index d0cfe4c10..b291ae2b1 100644 --- a/workflow-service/src/main/java/com/redhat/parodos/workflow/execution/aspect/WorkFlowExecutionAspect.java +++ b/workflow-service/src/main/java/com/redhat/parodos/workflow/execution/aspect/WorkFlowExecutionAspect.java @@ -20,14 +20,13 @@ import com.redhat.parodos.workflow.definition.entity.WorkFlowDefinition; import com.redhat.parodos.workflow.definition.entity.WorkFlowTaskDefinition; import com.redhat.parodos.workflow.definition.repository.WorkFlowDefinitionRepository; -import com.redhat.parodos.workflow.definition.repository.WorkFlowWorkRepository; import com.redhat.parodos.workflow.enums.WorkFlowStatus; import com.redhat.parodos.workflow.enums.WorkFlowType; +import com.redhat.parodos.workflow.exceptions.WorkflowExecutionNotFoundException; import com.redhat.parodos.workflow.execution.continuation.WorkFlowContinuationServiceImpl; import com.redhat.parodos.workflow.execution.entity.WorkFlowExecution; import com.redhat.parodos.workflow.execution.entity.WorkFlowExecutionContext; import com.redhat.parodos.workflow.execution.repository.WorkFlowRepository; -import com.redhat.parodos.workflow.execution.repository.WorkFlowTaskRepository; import com.redhat.parodos.workflow.execution.scheduler.WorkFlowSchedulerServiceImpl; import com.redhat.parodos.workflow.execution.service.WorkFlowServiceImpl; import com.redhat.parodos.workflow.util.WorkFlowDTOUtil; @@ -63,8 +62,6 @@ @Slf4j public class WorkFlowExecutionAspect { - private final WorkFlowTaskRepository workFlowTaskRepository; - private final WorkFlowRepository workFlowRepository; private final WorkFlowServiceImpl workFlowService; @@ -75,20 +72,15 @@ public class WorkFlowExecutionAspect { private final WorkFlowContinuationServiceImpl workFlowContinuationServiceImpl; - private final WorkFlowWorkRepository workFlowWorkRepository; - public WorkFlowExecutionAspect(WorkFlowServiceImpl workFlowService, WorkFlowSchedulerServiceImpl workFlowSchedulerService, WorkFlowDefinitionRepository workFlowDefinitionRepository, WorkFlowRepository workFlowRepository, - WorkFlowContinuationServiceImpl workFlowContinuationServiceImpl, - WorkFlowTaskRepository workFlowTaskRepository, WorkFlowWorkRepository workFlowWorkRepository) { + WorkFlowContinuationServiceImpl workFlowContinuationServiceImpl) { this.workFlowService = workFlowService; this.workFlowSchedulerService = workFlowSchedulerService; this.workFlowDefinitionRepository = workFlowDefinitionRepository; this.workFlowRepository = workFlowRepository; this.workFlowContinuationServiceImpl = workFlowContinuationServiceImpl; - this.workFlowTaskRepository = workFlowTaskRepository; - this.workFlowWorkRepository = workFlowWorkRepository; } /** @@ -107,56 +99,52 @@ public void pointcutScope() { */ @Around("pointcutScope() && args(workContext)") public WorkReport executeAroundAdvice(ProceedingJoinPoint proceedingJoinPoint, WorkContext workContext) { - WorkReport report = null; - String workFlowName = ((WorkFlow) proceedingJoinPoint.getTarget()).getName(); - log.info("Before invoking execute() on workflow: {} with workContext: {}", workFlowName, workContext); + WorkReport report; + String workflowName = ((WorkFlow) proceedingJoinPoint.getTarget()).getName(); + log.info("Before invoking execute() on workflow: {} with workContext: {}", workflowName, workContext); - // get workflow definition entity - WorkFlowDefinition workFlowDefinition = this.workFlowDefinitionRepository.findFirstByName(workFlowName); + /* get workflow definition entity */ + WorkFlowDefinition workFlowDefinition = this.workFlowDefinitionRepository.findFirstByName(workflowName); - boolean isMaster = workFlowWorkRepository.findByWorkDefinitionId(workFlowDefinition.getId()).isEmpty() - && !workFlowDefinition.getType().equals(WorkFlowType.CHECKER) - && !workFlowDefinition.getType().equals(WorkFlowType.ESCALATION); + String masterWorkflowName = WorkContextDelegate.read(workContext, + WorkContextDelegate.ProcessType.WORKFLOW_DEFINITION, WorkContextDelegate.Resource.NAME).toString(); + boolean isMaster = workflowName.equals(masterWorkflowName); - // get/set master WorkFlowExecution + WorkFlowExecution workFlowExecution; + WorkFlowExecution masterWorkFlowExecution = null; + String arguments = WorkFlowDTOUtil.writeObjectValueAsString( + WorkContextDelegate.read(workContext, WorkContextDelegate.ProcessType.WORKFLOW_EXECUTION, workflowName, + WorkContextDelegate.Resource.ARGUMENTS)); + UUID projectId = UUID.fromString(WorkContextDelegate + .read(workContext, WorkContextDelegate.ProcessType.PROJECT, WorkContextDelegate.Resource.ID) + .toString()); + + // get master WorkFlowExecution, this is the first time execution for master + // workflow if return null UUID masterWorkFlowExecutionId = Optional.ofNullable(WorkContextDelegate.read(workContext, WorkContextDelegate.ProcessType.WORKFLOW_EXECUTION, WorkContextDelegate.Resource.ID)) .map(id -> UUID.fromString(id.toString())).orElse(null); - WorkFlowExecution workFlowExecution; if (masterWorkFlowExecutionId == null) { - /* - * this is first time execution for master workflow save and write execution - * id to workContext - */ - workFlowExecution = this.workFlowService - .saveWorkFlow( - UUID.fromString( - WorkContextDelegate.read(workContext, WorkContextDelegate.ProcessType.PROJECT, - WorkContextDelegate.Resource.ID).toString()), - workFlowDefinition.getId(), WorkFlowStatus.IN_PROGRESS, null); - masterWorkFlowExecutionId = workFlowExecution.getId(); - WorkContextDelegate.write(workContext, WorkContextDelegate.ProcessType.WORKFLOW_EXECUTION, - WorkContextDelegate.Resource.ID, workFlowExecution.getId()); + workFlowExecution = handleFirstTimeMainWorkFlowExecution(projectId, workFlowDefinition, arguments, + workContext); } else { - WorkFlowExecution masterWorkFlowExecution = workFlowRepository.findById(masterWorkFlowExecutionId).get(); - - // get the workflow execution if it's to continue - if (isMaster) - workFlowExecution = masterWorkFlowExecution; - else - workFlowExecution = workFlowRepository.findFirstByWorkFlowDefinitionIdAndMasterWorkFlowExecution( - workFlowDefinition.getId(), masterWorkFlowExecution); - - if (workFlowExecution == null) { - workFlowExecution = this.workFlowService.saveWorkFlow( - UUID.fromString(WorkContextDelegate.read(workContext, WorkContextDelegate.ProcessType.PROJECT, - WorkContextDelegate.Resource.ID).toString()), - workFlowDefinition.getId(), WorkFlowStatus.IN_PROGRESS, masterWorkFlowExecution); - } - else if (workFlowExecution.getStatus().equals(WorkFlowStatus.COMPLETED)) { - // skip the workflow if it's already successful + masterWorkFlowExecution = workFlowRepository.findById(masterWorkFlowExecutionId) + .orElseThrow(() -> new WorkflowExecutionNotFoundException( + "masterWorkFlow not found for sub-workflow: " + workflowName)); + + // get the workflow execution if this is triggered by continuation service + WorkFlowExecution finalMasterWorkFlowExecution = masterWorkFlowExecution; + workFlowExecution = isMaster ? masterWorkFlowExecution + : Optional + .ofNullable(workFlowRepository.findFirstByWorkFlowDefinitionIdAndMasterWorkFlowExecution( + workFlowDefinition.getId(), masterWorkFlowExecution)) + .orElseGet(() -> this.workFlowService.saveWorkFlow(projectId, workFlowDefinition.getId(), + WorkFlowStatus.IN_PROGRESS, finalMasterWorkFlowExecution, arguments)); + + if (workFlowExecution.getStatus().equals(WorkFlowStatus.COMPLETED)) { + // skip the workflow if it is already successful if (workFlowDefinition.getType().equals(WorkFlowType.CHECKER)) { workFlowSchedulerService.stop((WorkFlow) proceedingJoinPoint.getTarget()); } @@ -164,99 +152,130 @@ else if (workFlowExecution.getStatus().equals(WorkFlowStatus.COMPLETED)) { } } - if (!isMaster) - WorkContextDelegate.write(workContext, WorkContextDelegate.ProcessType.WORKFLOW_EXECUTION, workFlowName, - WorkContextDelegate.Resource.ID, workFlowExecution.getId().toString()); - workFlowDefinition.getWorkFlowTaskDefinitions() - .forEach(workFlowTaskDefinitionEntity -> WorkContextDelegate.write(workContext, - WorkContextDelegate.ProcessType.WORKFLOW_TASK_EXECUTION, workFlowTaskDefinitionEntity.getName(), - WorkContextDelegate.Resource.ID, workFlowTaskDefinitionEntity.getId().toString())); try { report = (WorkReport) proceedingJoinPoint.proceed(); + log.info("Workflow {} is {}!", workflowName, report.getStatus().name()); } catch (Throwable e) { - log.error("Workflow {} has failed! with error: {}", workFlowName, e); + log.error("Workflow {} has failed! with error: {}", workflowName, e.getMessage()); report = new DefaultWorkReport(WorkStatus.FAILED, workContext); } - log.info("Workflow {} is {}!", workFlowName, report.getStatus().name()); + // update workflow execution entity workFlowExecution.setStatus(WorkFlowStatus.valueOf(report.getStatus().name())); workFlowExecution.setEndDate(new Date()); - workFlowExecution.setArguments(WorkFlowDTOUtil.writeObjectValueAsString(WorkContextDelegate.read(workContext, - WorkContextDelegate.ProcessType.WORKFLOW_EXECUTION, WorkContextDelegate.Resource.ARGUMENTS))); - if (!WorkFlowType.CHECKER.equals(workFlowDefinition.getType()) - && !WorkFlowType.ESCALATION.equals(workFlowDefinition.getType())) { - // save workContext to execution if this is master workflow - WorkFlowExecution masterWorkFlowExecution; - if (masterWorkFlowExecutionId == null) { - workFlowExecution.setWorkFlowExecutionContext(WorkFlowExecutionContext.builder() - .masterWorkFlowExecution(workFlowExecution).workContext(workContext).build()); - masterWorkFlowExecution = workFlowExecution; - - } - else { - masterWorkFlowExecution = workFlowRepository.findById(masterWorkFlowExecutionId).get(); - } - /* - * if this is infrastructure/assessment workflow, fail it and persist as - * 'pending' if any of its checkers' execution is not successful/not started - */ - Set workFlowCheckerMappingDefinitions = workFlowDefinition - .getWorkFlowTaskDefinitions().stream() - .map(WorkFlowTaskDefinition::getWorkFlowCheckerMappingDefinition).filter(Objects::nonNull) - .collect(Collectors.toSet()); - - if (workFlowCheckerMappingDefinitions.stream() - .map(workFlowCheckerDefinition -> workFlowRepository - .findFirstByWorkFlowDefinitionIdAndMasterWorkFlowExecution( - workFlowCheckerDefinition.getCheckWorkFlow().getId(), masterWorkFlowExecution)) - .anyMatch(checkerExecution -> checkerExecution == null - || !checkerExecution.getStatus().equals(WorkFlowStatus.COMPLETED))) { - log.info("failed wf: {}", workFlowName); - workFlowExecution.setStatus(WorkFlowStatus.PENDING); - workFlowService.updateWorkFlow(workFlowExecution); - return new DefaultWorkReport(WorkStatus.FAILED, workContext); - } - workFlowService.updateWorkFlow(workFlowExecution); + WorkReport workReport = postExecution(isMaster, workFlowDefinition, (WorkFlow) proceedingJoinPoint.getTarget(), + report.getStatus(), workContext, workFlowExecution, masterWorkFlowExecution); - } - else { - /* - * if this workflow is a checker, schedule workflow checker for dynamic run on - * cron expression or stop if done - */ - workFlowService.updateWorkFlow(workFlowExecution); - startOrStopWorkFlowCheckerOnSchedule(workFlowDefinition.getName(), - (WorkFlow) proceedingJoinPoint.getTarget(), workFlowDefinition.getCheckerWorkFlowDefinition(), - report.getStatus(), workContext, workFlowExecution.getProjectId().toString(), - masterWorkFlowExecutionId, - WorkContextDelegate.read(workContext, WorkContextDelegate.ProcessType.WORKFLOW_DEFINITION, - WorkContextDelegate.Resource.NAME).toString()); - } - return report; + return workReport == null ? report : workReport; } - private void startOrStopWorkFlowCheckerOnSchedule(String workFlowName, WorkFlow workFlow, + private void startOrStopWorkFlowCheckerOnSchedule(WorkFlow workFlow, WorkFlowCheckerMappingDefinition workFlowCheckerMappingDefinition, WorkStatus workStatus, - WorkContext workContext, String projectId, UUID masterWorkFlowExecution, String masterWorkFlowName) { + WorkContext workContext, String projectId, WorkFlowExecution masterWorkFlowExecution) { if (workStatus != WorkStatus.COMPLETED) { - log.info("Schedule workflow checker: {} to run per cron expression: {}", workFlowName, + log.info("Schedule workflow checker: {} to run per cron expression: {}", workFlow.getName(), workFlowCheckerMappingDefinition.getCronExpression()); workFlowSchedulerService.schedule(workFlow, workContext, workFlowCheckerMappingDefinition.getCronExpression()); return; } - log.info("Stop workflow checker: {} schedule", workFlowName); + log.info("Stop workflow checker: {} schedule", workFlow.getName()); workFlowSchedulerService.stop(workFlow); + String masterWorkFlowName = WorkContextDelegate.read(workContext, + WorkContextDelegate.ProcessType.WORKFLOW_DEFINITION, WorkContextDelegate.Resource.NAME).toString(); /* * if this workflow is checker and it's successful, call continuation service to * restart master workflow execution with same execution Id */ workFlowContinuationServiceImpl.continueWorkFlow(projectId, masterWorkFlowName, workContext, - masterWorkFlowExecution); + masterWorkFlowExecution.getId()); + } + + private WorkFlowExecution handleFirstTimeMainWorkFlowExecution(UUID projectId, + WorkFlowDefinition workFlowDefinition, String arguments, WorkContext workContext) { + + /* + * if this is the first time execution for master workflow, persist it and write + * its execution id to workContext + */ + WorkFlowExecution workFlowExecution = this.workFlowService.saveWorkFlow(projectId, workFlowDefinition.getId(), + WorkFlowStatus.IN_PROGRESS, null, arguments); + WorkContextDelegate.write(workContext, WorkContextDelegate.ProcessType.WORKFLOW_EXECUTION, + WorkContextDelegate.Resource.ID, workFlowExecution.getId()); + return workFlowExecution; + } + + private WorkReport postExecution(boolean isMaster, WorkFlowDefinition workFlowDefinition, WorkFlow workFlow, + WorkStatus workStatus, WorkContext workContext, WorkFlowExecution workFlowExecution, + WorkFlowExecution masterWorkFlowExecution) { + WorkReport workReport = null; + switch (workFlowDefinition.getType()) { + case INFRASTRUCTURE: + case ASSESSMENT: + workReport = handlePostWorkflowExecution(isMaster, workFlowExecution, workContext, workFlowDefinition, + masterWorkFlowExecution); + break; + + case CHECKER: + handlePostCheckerExecution(workFlowDefinition, workFlow, workFlowExecution, workStatus, workContext, + masterWorkFlowExecution); + break; + default: + break; + } + return workReport; + } + + private WorkReport handlePostWorkflowExecution(boolean isMaster, WorkFlowExecution workFlowExecution, + WorkContext workContext, WorkFlowDefinition workFlowDefinition, WorkFlowExecution masterWorkFlowExecution) { + WorkReport report = null; + if (isMaster) { + workFlowExecution.setWorkFlowExecutionContext(Optional + .ofNullable(workFlowExecution.getWorkFlowExecutionContext()).map(workFlowExecutionContext -> { + workFlowExecutionContext.setWorkContext(workContext); + return workFlowExecutionContext; + }).orElse(WorkFlowExecutionContext.builder().masterWorkFlowExecution(workFlowExecution) + .workContext(workContext).build())); + } + + /* + * if this is infrastructure/assessment workflow, fail it and persist as 'pending' + * if any of its sub work's execution is pending + */ + Set workFlowCheckerMappingDefinitions = workFlowDefinition + .getWorkFlowTaskDefinitions().stream().map(WorkFlowTaskDefinition::getWorkFlowCheckerMappingDefinition) + .filter(Objects::nonNull).collect(Collectors.toSet()); + + if (workFlowCheckerMappingDefinitions.stream() + .map(workFlowCheckerDefinition -> workFlowRepository + .findFirstByWorkFlowDefinitionIdAndMasterWorkFlowExecution( + workFlowCheckerDefinition.getCheckWorkFlow().getId(), masterWorkFlowExecution)) + .anyMatch(checkerExecution -> checkerExecution == null + || !WorkFlowStatus.COMPLETED.equals(checkerExecution.getStatus()))) { + log.info("fail workflow: {} because it has pending/running checker(s)", workFlowDefinition.getName()); + workFlowExecution.setStatus(WorkFlowStatus.PENDING); + report = new DefaultWorkReport(WorkStatus.FAILED, workContext); + } + + workFlowService.updateWorkFlow(workFlowExecution); + return report; + } + + public void handlePostCheckerExecution(WorkFlowDefinition workFlowDefinition, WorkFlow workFlow, + WorkFlowExecution workFlowExecution, WorkStatus workStatus, WorkContext workContext, + WorkFlowExecution masterWorkFlowExecution) { + + workFlowService.updateWorkFlow(workFlowExecution); + /* + * if this workflow is a checker, schedule workflow checker for dynamic run on + * cron expression or stop if done + */ + startOrStopWorkFlowCheckerOnSchedule(workFlow, workFlowDefinition.getCheckerWorkFlowDefinition(), workStatus, + workContext, workFlowExecution.getProjectId().toString(), masterWorkFlowExecution); } } diff --git a/workflow-service/src/main/java/com/redhat/parodos/workflow/execution/aspect/WorkFlowTaskExecutionAspect.java b/workflow-service/src/main/java/com/redhat/parodos/workflow/execution/aspect/WorkFlowTaskExecutionAspect.java index 47094d01e..c0c97f702 100644 --- a/workflow-service/src/main/java/com/redhat/parodos/workflow/execution/aspect/WorkFlowTaskExecutionAspect.java +++ b/workflow-service/src/main/java/com/redhat/parodos/workflow/execution/aspect/WorkFlowTaskExecutionAspect.java @@ -15,36 +15,36 @@ */ package com.redhat.parodos.workflow.execution.aspect; -import java.util.Date; -import java.util.List; -import java.util.UUID; - -import org.aspectj.lang.ProceedingJoinPoint; -import org.aspectj.lang.annotation.Around; -import org.aspectj.lang.annotation.Aspect; -import org.aspectj.lang.annotation.Pointcut; -import org.springframework.stereotype.Component; - import com.redhat.parodos.workflow.context.WorkContextDelegate; import com.redhat.parodos.workflow.definition.entity.WorkFlowCheckerMappingDefinition; import com.redhat.parodos.workflow.definition.entity.WorkFlowTaskDefinition; import com.redhat.parodos.workflow.definition.repository.WorkFlowTaskDefinitionRepository; +import com.redhat.parodos.workflow.exceptions.WorkflowExecutionNotFoundException; import com.redhat.parodos.workflow.execution.entity.WorkFlowExecution; import com.redhat.parodos.workflow.execution.entity.WorkFlowTaskExecution; import com.redhat.parodos.workflow.execution.repository.WorkFlowRepository; import com.redhat.parodos.workflow.execution.scheduler.WorkFlowSchedulerServiceImpl; import com.redhat.parodos.workflow.execution.service.WorkFlowServiceImpl; +import com.redhat.parodos.workflow.task.BaseWorkFlowTask; import com.redhat.parodos.workflow.task.WorkFlowTask; import com.redhat.parodos.workflow.task.enums.WorkFlowTaskStatus; -import com.redhat.parodos.workflow.task.infrastructure.BaseInfrastructureWorkFlowTask; import com.redhat.parodos.workflow.util.WorkFlowDTOUtil; import com.redhat.parodos.workflows.work.DefaultWorkReport; import com.redhat.parodos.workflows.work.WorkContext; import com.redhat.parodos.workflows.work.WorkReport; import com.redhat.parodos.workflows.work.WorkStatus; import com.redhat.parodos.workflows.workflow.WorkFlow; - import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.UUID; /** * Aspect pointcut to perform state management for a workflow task executions @@ -99,13 +99,14 @@ public WorkReport executeAroundAdviceTask(ProceedingJoinPoint proceedingJoinPoin WorkFlowTaskDefinition workFlowTaskDefinition = workFlowTaskDefinitionRepository .findFirstByName(workFlowTaskName); - // skip the task if it's already successful UUID masterWorkFlowExecutionId = UUID.fromString(WorkContextDelegate .read(workContext, WorkContextDelegate.ProcessType.WORKFLOW_EXECUTION, WorkContextDelegate.Resource.ID) .toString()); - WorkFlowExecution masterWorkFlowExecution = workFlowRepository.findById(masterWorkFlowExecutionId).get(); - // get the workflow if it's executed again from continuation + WorkFlowExecution masterWorkFlowExecution = workFlowRepository.findById(masterWorkFlowExecutionId).orElseThrow( + () -> new WorkflowExecutionNotFoundException("masterWorkFlow not found for task: " + workFlowTaskName)); + + // get the workflow execution if it's executed again from continuation WorkFlowExecution workFlowExecution = handleParentWorkflowUseCase(workContext, workFlowTaskDefinition, masterWorkFlowExecution); WorkFlowTaskExecution workFlowTaskExecution = workFlowService.getWorkFlowTask(workFlowExecution.getId(), @@ -113,26 +114,33 @@ public WorkReport executeAroundAdviceTask(ProceedingJoinPoint proceedingJoinPoin if (workFlowTaskExecution == null) { workFlowTaskExecution = workFlowService.saveWorkFlowTask( // @formatter:off - WorkFlowDTOUtil.writeObjectValueAsString(WorkContextDelegate.read( - workContext, - WorkContextDelegate.ProcessType.WORKFLOW_TASK_EXECUTION, - workFlowTaskName, - WorkContextDelegate.Resource.ARGUMENTS)), - workFlowTaskDefinition.getId(), - workFlowExecution.getId(), - WorkFlowTaskStatus.IN_PROGRESS); - // @formatter:on + WorkFlowDTOUtil.writeObjectValueAsString(WorkContextDelegate.read( + workContext, + WorkContextDelegate.ProcessType.WORKFLOW_TASK_EXECUTION, + workFlowTaskName, + WorkContextDelegate.Resource.ARGUMENTS)), + workFlowTaskDefinition.getId(), + workFlowExecution.getId(), + WorkFlowTaskStatus.IN_PROGRESS); + // @formatter:on } - else if (workFlowTaskExecution.getStatus().equals(WorkFlowTaskStatus.COMPLETED)) + else if (WorkFlowTaskStatus.IN_PROGRESS.equals(workFlowTaskExecution.getStatus())) + // fail the task if it's processed by other thread + return new DefaultWorkReport(WorkStatus.FAILED, workContext); + else if (WorkFlowTaskStatus.COMPLETED.equals(workFlowTaskExecution.getStatus())) // skip the task if it's already successful return new DefaultWorkReport(WorkStatus.COMPLETED, workContext); try { report = (WorkReport) proceedingJoinPoint.proceed(); + if (report == null || report.getStatus() == null) + throw new NullPointerException("task execution not returns status: " + workFlowTaskName); } catch (Throwable e) { - log.error("Workflow task execution {} has failed!", workFlowTaskName); + log.error("Workflow task execution {} has failed! error message: {}", workFlowTaskName, e.getMessage()); + report = new DefaultWorkReport(WorkStatus.FAILED, workContext); } + WorkContextDelegate.write(workContext, WorkContextDelegate.ProcessType.WORKFLOW_TASK_EXECUTION, workFlowTaskName, WorkContextDelegate.Resource.STATUS, report.getStatus().name()); @@ -140,49 +148,46 @@ else if (workFlowTaskExecution.getStatus().equals(WorkFlowTaskStatus.COMPLETED)) workFlowTaskExecution.setLastUpdateDate(new Date()); workFlowService.updateWorkFlowTask(workFlowTaskExecution); - handleChecker(proceedingJoinPoint, workContext, workFlowTaskDefinition, masterWorkFlowExecution); + /* + * if this task is successful, and it has checker; then schedule workflow checker + * for dynamic run on cron expression + */ + if (WorkStatus.COMPLETED.equals(report.getStatus()) + && workFlowTaskDefinition.getWorkFlowCheckerMappingDefinition() != null) { + handleChecker(proceedingJoinPoint, workContext, workFlowTaskDefinition, masterWorkFlowExecution); + return new DefaultWorkReport(WorkStatus.FAILED, workContext); + } return report; } // Check the WorkFlow for Checkers private void handleChecker(ProceedingJoinPoint proceedingJoinPoint, WorkContext workContext, WorkFlowTaskDefinition workFlowTaskDefinition, WorkFlowExecution masterWorkFlowExecution) { - /* - * if this task has checker schedule workflow checker for dynamic run on cron - * expression or stop if done - */ - if (workFlowTaskDefinition.getWorkFlowCheckerMappingDefinition() != null) { - // if this task has no running checker - WorkFlowExecution checkerWorkFlowExecution = workFlowRepository - .findFirstByWorkFlowDefinitionIdAndMasterWorkFlowExecution( - workFlowTaskDefinition.getWorkFlowCheckerMappingDefinition().getId(), - masterWorkFlowExecution); - if (checkerWorkFlowExecution == null) { - // schedule workflow checker for dynamic run on cron expression - List checkerWorkFlows = ((BaseInfrastructureWorkFlowTask) proceedingJoinPoint.getTarget()) - .getWorkFlowCheckers(); - startCheckerOnSchedule( - workFlowTaskDefinition.getWorkFlowCheckerMappingDefinition().getCheckWorkFlow().getName(), - checkerWorkFlows, workFlowTaskDefinition.getWorkFlowCheckerMappingDefinition(), workContext); - } + + // if this task has no running checker + WorkFlowExecution checkerWorkFlowExecution = workFlowRepository + .findFirstByWorkFlowDefinitionIdAndMasterWorkFlowExecution( + workFlowTaskDefinition.getWorkFlowCheckerMappingDefinition().getId(), masterWorkFlowExecution); + if (checkerWorkFlowExecution == null) { + // schedule workflow checker for dynamic run on cron expression + List checkerWorkFlows = ((BaseWorkFlowTask) proceedingJoinPoint.getTarget()) + .getWorkFlowCheckers(); + startCheckerOnSchedule( + workFlowTaskDefinition.getWorkFlowCheckerMappingDefinition().getCheckWorkFlow().getName(), + checkerWorkFlows, workFlowTaskDefinition.getWorkFlowCheckerMappingDefinition(), workContext); } } // Deal with any logic related to Parent WorkFlows private WorkFlowExecution handleParentWorkflowUseCase(WorkContext workContext, WorkFlowTaskDefinition workFlowTaskDefinition, WorkFlowExecution masterWorkFlowExecution) { - WorkFlowExecution workFlowExecution; - boolean isParentWorkFlowMaster = workFlowTaskDefinition.getWorkFlowDefinition().getName().equalsIgnoreCase( + return workFlowTaskDefinition.getWorkFlowDefinition().getName().equalsIgnoreCase( WorkContextDelegate.read(workContext, WorkContextDelegate.ProcessType.WORKFLOW_DEFINITION, - WorkContextDelegate.Resource.NAME).toString()); - if (isParentWorkFlowMaster) { - workFlowExecution = masterWorkFlowExecution; - } - else { - workFlowExecution = workFlowRepository.findFirstByWorkFlowDefinitionIdAndMasterWorkFlowExecution( - workFlowTaskDefinition.getWorkFlowDefinition().getId(), masterWorkFlowExecution); - } - return workFlowExecution; + WorkContextDelegate.Resource.NAME).toString()) + ? masterWorkFlowExecution + : workFlowRepository.findFirstByWorkFlowDefinitionIdAndMasterWorkFlowExecution( + workFlowTaskDefinition.getWorkFlowDefinition().getId(), + masterWorkFlowExecution); } // Iterate through the all the Checkers in the workflow and start them based on their diff --git a/workflow-service/src/main/java/com/redhat/parodos/workflow/execution/dto/WorkStatusResponseDTO.java b/workflow-service/src/main/java/com/redhat/parodos/workflow/execution/dto/WorkStatusResponseDTO.java index 73b6a0e0a..b2e551989 100644 --- a/workflow-service/src/main/java/com/redhat/parodos/workflow/execution/dto/WorkStatusResponseDTO.java +++ b/workflow-service/src/main/java/com/redhat/parodos/workflow/execution/dto/WorkStatusResponseDTO.java @@ -17,7 +17,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; -import com.redhat.parodos.workflow.enums.WorkStatus; +import com.redhat.parodos.workflow.enums.ParodosWorkStatus; import com.redhat.parodos.workflow.enums.WorkType; import com.redhat.parodos.workflow.execution.entity.WorkFlowExecution; import lombok.AllArgsConstructor; @@ -45,7 +45,7 @@ public class WorkStatusResponseDTO { private WorkType type; - private WorkStatus status; + private ParodosWorkStatus status; @JsonInclude(JsonInclude.Include.NON_EMPTY) private List works; diff --git a/workflow-service/src/main/java/com/redhat/parodos/workflow/execution/service/WorkFlowService.java b/workflow-service/src/main/java/com/redhat/parodos/workflow/execution/service/WorkFlowService.java index 9fb590924..2988902ad 100644 --- a/workflow-service/src/main/java/com/redhat/parodos/workflow/execution/service/WorkFlowService.java +++ b/workflow-service/src/main/java/com/redhat/parodos/workflow/execution/service/WorkFlowService.java @@ -37,7 +37,7 @@ public interface WorkFlowService { WorkFlowExecution getWorkFlowById(UUID workFlowExecutionId); WorkFlowExecution saveWorkFlow(UUID projectId, UUID workFlowDefinitionId, WorkFlowStatus workFlowStatus, - WorkFlowExecution masterWorkFlowExecution); + WorkFlowExecution masterWorkFlowExecution, String arguments); WorkFlowExecution updateWorkFlow(WorkFlowExecution workFlowExecution); diff --git a/workflow-service/src/main/java/com/redhat/parodos/workflow/execution/service/WorkFlowServiceDelegate.java b/workflow-service/src/main/java/com/redhat/parodos/workflow/execution/service/WorkFlowServiceDelegate.java index 43cd5913a..03a0c1c19 100644 --- a/workflow-service/src/main/java/com/redhat/parodos/workflow/execution/service/WorkFlowServiceDelegate.java +++ b/workflow-service/src/main/java/com/redhat/parodos/workflow/execution/service/WorkFlowServiceDelegate.java @@ -21,6 +21,7 @@ import com.redhat.parodos.workflow.definition.repository.WorkFlowDefinitionRepository; import com.redhat.parodos.workflow.definition.repository.WorkFlowTaskDefinitionRepository; import com.redhat.parodos.workflow.definition.repository.WorkFlowWorkRepository; +import com.redhat.parodos.workflow.enums.ParodosWorkStatus; import com.redhat.parodos.workflow.enums.WorkFlowStatus; import com.redhat.parodos.workflow.enums.WorkType; import com.redhat.parodos.workflow.execution.dto.WorkStatusResponseDTO; @@ -100,9 +101,8 @@ private void buildWorkFlowStatusDTO(WorkFlowExecution workFlowExecution, WorkFlo // build workflow status DTO workStatusResponseDTOList.add(WorkStatusResponseDTO.builder().name(workFlowDefinition.getName()) .type(WorkType.WORKFLOW) - .status(WorkFlowStatus.IN_PROGRESS.equals(workFlowExecution.getStatus()) - ? com.redhat.parodos.workflow.enums.WorkStatus.PENDING - : com.redhat.parodos.workflow.enums.WorkStatus.valueOf(workFlowExecution.getStatus().name())) + .status(WorkFlowStatus.IN_PROGRESS.equals(workFlowExecution.getStatus()) ? ParodosWorkStatus.PENDING + : ParodosWorkStatus.valueOf(workFlowExecution.getStatus().name())) .workExecution(workFlowExecution).numberOfWorks(workFlowDefinition.getNumberOfWorks()) .works(new ArrayList<>()).build()); @@ -153,10 +153,9 @@ private WorkStatusResponseDTO getWorkStatusResponseDTOFromWorkFlow(WorkFlowWorkD /* * the workflow execution might be null when there is pending checker before it */ - com.redhat.parodos.workflow.enums.WorkStatus workStatus = workExecution == null - || WorkFlowStatus.IN_PROGRESS.equals(workExecution.getStatus()) - ? com.redhat.parodos.workflow.enums.WorkStatus.PENDING - : com.redhat.parodos.workflow.enums.WorkStatus.valueOf(workExecution.getStatus().name()); + ParodosWorkStatus workStatus = workExecution == null + || WorkFlowStatus.IN_PROGRESS.equals(workExecution.getStatus()) ? ParodosWorkStatus.PENDING + : ParodosWorkStatus.valueOf(workExecution.getStatus().name()); return WorkStatusResponseDTO.builder().name(workFlowDefinition.getName()).type(WorkType.WORKFLOW) .status(workStatus).works(new ArrayList<>()).workExecution(workExecution) @@ -175,13 +174,12 @@ private WorkStatusResponseDTO getWorkStatusResponseDTOFromWorkFlowTask( Optional workFlowTaskExecutionOptional = workFlowTaskExecutions.stream() .max(Comparator.comparing(WorkFlowTaskExecution::getStartDate)); - com.redhat.parodos.workflow.enums.WorkStatus workStatus = com.redhat.parodos.workflow.enums.WorkStatus.PENDING; + ParodosWorkStatus workStatus = ParodosWorkStatus.PENDING; if (workFlowTaskExecutionOptional.isPresent()) { workStatus = WorkFlowTaskStatus.IN_PROGRESS.equals(workFlowTaskExecutionOptional.get().getStatus()) - ? com.redhat.parodos.workflow.enums.WorkStatus.PENDING - : com.redhat.parodos.workflow.enums.WorkStatus - .valueOf(workFlowTaskExecutionOptional.get().getStatus().name()); + ? ParodosWorkStatus.PENDING + : ParodosWorkStatus.valueOf(workFlowTaskExecutionOptional.get().getStatus().name()); } return WorkStatusResponseDTO.builder().name(workFlowTaskDefinition.getName()).type(WorkType.TASK) diff --git a/workflow-service/src/main/java/com/redhat/parodos/workflow/execution/service/WorkFlowServiceImpl.java b/workflow-service/src/main/java/com/redhat/parodos/workflow/execution/service/WorkFlowServiceImpl.java index b338837ba..0f7f3d616 100644 --- a/workflow-service/src/main/java/com/redhat/parodos/workflow/execution/service/WorkFlowServiceImpl.java +++ b/workflow-service/src/main/java/com/redhat/parodos/workflow/execution/service/WorkFlowServiceImpl.java @@ -24,6 +24,7 @@ import com.redhat.parodos.workflow.definition.repository.WorkFlowWorkRepository; import com.redhat.parodos.workflow.enums.WorkFlowStatus; import com.redhat.parodos.workflow.enums.WorkFlowType; +import com.redhat.parodos.workflow.exceptions.WorkflowPersistenceFailedException; import com.redhat.parodos.workflow.execution.dto.WorkFlowRequestDTO; import com.redhat.parodos.workflow.execution.dto.WorkFlowStatusResponseDTO; import com.redhat.parodos.workflow.execution.dto.WorkStatusResponseDTO; @@ -39,6 +40,7 @@ import com.redhat.parodos.workflows.work.WorkStatus; import com.redhat.parodos.workflows.workflow.WorkFlow; import lombok.extern.slf4j.Slf4j; +import org.springframework.dao.DataAccessException; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; import org.springframework.web.server.ResponseStatusException; @@ -125,10 +127,17 @@ public WorkFlowExecution getWorkFlowById(UUID workFlowExecutionId) { @Override public synchronized WorkFlowExecution saveWorkFlow(UUID projectId, UUID workFlowDefinitionId, - WorkFlowStatus workFlowStatus, WorkFlowExecution masterWorkFlowExecution) { - return workFlowRepository.save(WorkFlowExecution.builder().workFlowDefinitionId(workFlowDefinitionId) - .projectId(projectId).status(workFlowStatus).startDate(new Date()) - .masterWorkFlowExecution(masterWorkFlowExecution).build()); + WorkFlowStatus workFlowStatus, WorkFlowExecution masterWorkFlowExecution, String arguments) { + try { + return workFlowRepository.save(WorkFlowExecution.builder().workFlowDefinitionId(workFlowDefinitionId) + .projectId(projectId).status(workFlowStatus).startDate(new Date()).arguments(arguments) + .masterWorkFlowExecution(masterWorkFlowExecution).build()); + } + catch (DataAccessException | IllegalArgumentException e) { + log.error("failing persist workflow execution for: {} in master workflow execution: {}. error Message: {}", + workFlowDefinitionId, masterWorkFlowExecution.getId(), e.getMessage()); + throw new WorkflowPersistenceFailedException(e.getMessage()); + } } @Override @@ -175,14 +184,28 @@ public WorkFlowTaskExecution getWorkFlowTask(UUID workFlowExecutionId, UUID work @Override public synchronized WorkFlowTaskExecution saveWorkFlowTask(String arguments, UUID workFlowTaskDefinitionId, UUID workFlowExecutionId, WorkFlowTaskStatus workFlowTaskStatus) { - return workFlowTaskRepository.save(WorkFlowTaskExecution.builder().workFlowExecutionId(workFlowExecutionId) - .workFlowTaskDefinitionId(workFlowTaskDefinitionId).arguments(arguments).status(workFlowTaskStatus) - .startDate(new Date()).build()); + try { + return workFlowTaskRepository.save(WorkFlowTaskExecution.builder().workFlowExecutionId(workFlowExecutionId) + .workFlowTaskDefinitionId(workFlowTaskDefinitionId).arguments(arguments).status(workFlowTaskStatus) + .startDate(new Date()).build()); + } + catch (DataAccessException | IllegalArgumentException e) { + log.error("failing persist task execution for: {} in master workflow execution: {}. error Message: {}", + workFlowTaskDefinitionId, workFlowTaskDefinitionId, e.getMessage()); + throw new WorkflowPersistenceFailedException(e.getMessage()); + } } @Override public WorkFlowTaskExecution updateWorkFlowTask(WorkFlowTaskExecution workFlowTaskExecution) { - return workFlowTaskRepository.save(workFlowTaskExecution); + try { + return workFlowTaskRepository.save(workFlowTaskExecution); + } + catch (DataAccessException | IllegalArgumentException e) { + log.error("failed updating task execution for: {} in execution: {}. error Message: {}", + workFlowTaskExecution.getWorkFlowTaskDefinitionId(), workFlowTaskExecution.getId(), e.getMessage()); + throw new WorkflowPersistenceFailedException(e.getMessage()); + } } @Override diff --git a/workflow-service/src/test/java/com/redhat/parodos/workflow/execution/aspect/WorkFlowExecutionAspectTest.java b/workflow-service/src/test/java/com/redhat/parodos/workflow/execution/aspect/WorkFlowExecutionAspectTest.java index 55142c9cd..b537e3164 100644 --- a/workflow-service/src/test/java/com/redhat/parodos/workflow/execution/aspect/WorkFlowExecutionAspectTest.java +++ b/workflow-service/src/test/java/com/redhat/parodos/workflow/execution/aspect/WorkFlowExecutionAspectTest.java @@ -1,30 +1,14 @@ package com.redhat.parodos.workflow.execution.aspect; +import com.redhat.parodos.workflow.WorkFlowDelegate; import com.redhat.parodos.workflow.definition.entity.WorkFlowCheckerMappingDefinition; +import com.redhat.parodos.workflow.definition.entity.WorkFlowDefinition; import com.redhat.parodos.workflow.definition.entity.WorkFlowWorkDefinition; +import com.redhat.parodos.workflow.definition.repository.WorkFlowDefinitionRepository; import com.redhat.parodos.workflow.definition.repository.WorkFlowWorkRepository; import com.redhat.parodos.workflow.enums.WorkFlowStatus; import com.redhat.parodos.workflow.enums.WorkFlowType; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; - -import java.util.List; -import java.util.Optional; -import java.util.UUID; - import com.redhat.parodos.workflow.enums.WorkType; -import org.aspectj.lang.ProceedingJoinPoint; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.Mockito; - -import com.redhat.parodos.workflow.WorkFlowDelegate; -import com.redhat.parodos.workflow.definition.entity.WorkFlowDefinition; -import com.redhat.parodos.workflow.definition.repository.WorkFlowDefinitionRepository; import com.redhat.parodos.workflow.execution.continuation.WorkFlowContinuationServiceImpl; import com.redhat.parodos.workflow.execution.entity.WorkFlowExecution; import com.redhat.parodos.workflow.execution.repository.WorkFlowRepository; @@ -36,8 +20,23 @@ import com.redhat.parodos.workflows.work.WorkReport; import com.redhat.parodos.workflows.work.WorkStatus; import com.redhat.parodos.workflows.workflow.WorkFlow; +import org.aspectj.lang.ProceedingJoinPoint; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Mockito; import org.springframework.test.context.junit.jupiter.SpringExtension; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + @ExtendWith(SpringExtension.class) class WorkFlowExecutionAspectTest { @@ -87,8 +86,7 @@ public void initEach() { WorkFlow workflow = Mockito.mock(WorkFlow.class); WorkFlowDelegate workFlowDelegate = Mockito.mock(WorkFlowDelegate.class); this.workFlowExecutionAspect = new WorkFlowExecutionAspect(this.workFlowService, this.workFlowSchedulerService, - this.workFlowDefinitionRepository, this.workFlowRepository, this.workFlowContinuationService, - this.workFlowTaskRepository, this.workFlowWorkRepository); + this.workFlowDefinitionRepository, this.workFlowRepository, this.workFlowContinuationService); Mockito.when(workFlowDelegate.getWorkFlowExecutionByName(Mockito.any())) .thenReturn(Mockito.mock(WorkFlow.class)); Mockito.when(workflow.getName()).thenReturn(TEST); @@ -110,8 +108,8 @@ public void ExecuteAroundAdviceWithValidDataTest() { WorkFlowDefinition workFlowDefinition = getSampleWorkFlowDefinition(TEST); WorkFlowExecution workFlowExecution = getSampleWorkFlowExecution(); Mockito.when(this.workFlowDefinitionRepository.findFirstByName(Mockito.any())).thenReturn(workFlowDefinition); - Mockito.when(this.workFlowService.saveWorkFlow(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any())) - .thenReturn(getSampleWorkFlowExecution()); + Mockito.when(this.workFlowService.saveWorkFlow(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), + Mockito.any())).thenReturn(getSampleWorkFlowExecution()); ProceedingJoinPoint proceedingJoinPoint = Mockito.mock(ProceedingJoinPoint.class); WorkFlow workFlow = Mockito.mock(WorkFlow.class); @@ -157,8 +155,8 @@ void ExecuteAroundAdviceWithInProgressWorkFlowTest() { WorkFlowDefinition workFlowDefinition = getSampleWorkFlowDefinition(TEST); WorkFlowExecution workFlowExecution = getSampleWorkFlowExecution(); Mockito.when(this.workFlowDefinitionRepository.findFirstByName(Mockito.any())).thenReturn(workFlowDefinition); - Mockito.when(this.workFlowService.saveWorkFlow(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any())) - .thenReturn(getSampleWorkFlowExecution()); + Mockito.when(this.workFlowService.saveWorkFlow(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), + Mockito.any())).thenReturn(getSampleWorkFlowExecution()); Mockito.when(workFlowWorkRepository.findByWorkDefinitionId(Mockito.any())) .thenReturn(List.of(workFlowWorkDefinition)); ProceedingJoinPoint proceedingJoinPoint = Mockito.mock(ProceedingJoinPoint.class); diff --git a/workflow-service/src/test/java/com/redhat/parodos/workflow/execution/aspect/WorkFlowTaskExecutionAspectTest.java b/workflow-service/src/test/java/com/redhat/parodos/workflow/execution/aspect/WorkFlowTaskExecutionAspectTest.java index c15137c3d..b3b1b1938 100644 --- a/workflow-service/src/test/java/com/redhat/parodos/workflow/execution/aspect/WorkFlowTaskExecutionAspectTest.java +++ b/workflow-service/src/test/java/com/redhat/parodos/workflow/execution/aspect/WorkFlowTaskExecutionAspectTest.java @@ -136,7 +136,7 @@ public void executeAroundAdviceTaskWithSequentialFlowWhenTaskExecutionIsNotNull( // then assertNotNull(report); - assertEquals(report.getStatus(), WorkStatus.COMPLETED); + assertEquals(WorkStatus.COMPLETED, report.getStatus()); assertEquals(report.getWorkContext().get(WORKFLOW_EXECUTION_ID), workContext.get(WORKFLOW_EXECUTION_ID)); assertEquals(report.getWorkContext().get(WORKFLOW_TASK_DEFINITION_TESTTASK_ID), workContext.get(WORKFLOW_TASK_DEFINITION_TESTTASK_ID)); @@ -194,7 +194,7 @@ WorkFlowTaskExecution getSampleWorkFlowTaskExecution() { return new WorkFlowTaskExecution() { { setId(UUID.randomUUID()); - setStatus(WorkFlowTaskStatus.IN_PROGRESS); + setStatus(WorkFlowTaskStatus.PENDING); setWorkFlowExecutionId(getSampleWorkFlowExecution().getId()); setWorkFlowTaskDefinitionId(getSampleWorkFlowTaskDefinition(TEST_TASK).getId()); } diff --git a/workflow-service/src/test/java/com/redhat/parodos/workflow/execution/controller/WorkFlowControllerTest.java b/workflow-service/src/test/java/com/redhat/parodos/workflow/execution/controller/WorkFlowControllerTest.java index 990b74a8b..e51e5a5a5 100644 --- a/workflow-service/src/test/java/com/redhat/parodos/workflow/execution/controller/WorkFlowControllerTest.java +++ b/workflow-service/src/test/java/com/redhat/parodos/workflow/execution/controller/WorkFlowControllerTest.java @@ -3,8 +3,8 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.redhat.parodos.ControllerMockClient; +import com.redhat.parodos.workflow.enums.ParodosWorkStatus; import com.redhat.parodos.workflow.enums.WorkFlowStatus; -import com.redhat.parodos.workflow.enums.WorkStatus; import com.redhat.parodos.workflow.enums.WorkType; import com.redhat.parodos.workflow.execution.dto.WorkFlowCheckerTaskRequestDTO; import com.redhat.parodos.workflow.execution.dto.WorkFlowRequestDTO; @@ -123,12 +123,12 @@ public void testGetStatus() throws Exception { .workFlowExecutionId(masterWorkFlowExecutionId.toString()).status(WorkFlowStatus.IN_PROGRESS.name()) .workFlowName(testMasterWorkFlow) .works(List.of( - WorkStatusResponseDTO.builder().name(testSubWorkFlow1).status(WorkStatus.PENDING) + WorkStatusResponseDTO.builder().name(testSubWorkFlow1).status(ParodosWorkStatus.PENDING) .type(WorkType.WORKFLOW) .works(List.of(WorkStatusResponseDTO.builder().name(testSubWorkFlowTask1) - .status(WorkStatus.PENDING).type(WorkType.TASK).build())) + .status(ParodosWorkStatus.PENDING).type(WorkType.TASK).build())) .build(), - WorkStatusResponseDTO.builder().name(testWorkFlowTask1).status(WorkStatus.COMPLETED) + WorkStatusResponseDTO.builder().name(testWorkFlowTask1).status(ParodosWorkStatus.COMPLETED) .type(WorkType.TASK).build())) .build(); Mockito.when(workFlowService.getWorkFlowStatus(masterWorkFlowExecutionId)) @@ -146,17 +146,18 @@ public void testGetStatus() throws Exception { .andExpect(MockMvcResultMatchers.jsonPath("$.status", Matchers.is(WorkFlowStatus.IN_PROGRESS.name()))) .andExpect(MockMvcResultMatchers.jsonPath("$.works[0].name", Matchers.is(testSubWorkFlow1))) .andExpect(MockMvcResultMatchers.jsonPath("$.works[0].type", Matchers.is(WorkType.WORKFLOW.name()))) - .andExpect(MockMvcResultMatchers.jsonPath("$.works[0].status", Matchers.is(WorkStatus.PENDING.name()))) + .andExpect(MockMvcResultMatchers.jsonPath("$.works[0].status", + Matchers.is(ParodosWorkStatus.PENDING.name()))) .andExpect( MockMvcResultMatchers.jsonPath("$.works[0].works[0].name", Matchers.is(testSubWorkFlowTask1))) .andExpect(MockMvcResultMatchers.jsonPath("$.works[0].works[0].status", - Matchers.is(WorkStatus.PENDING.name()))) + Matchers.is(ParodosWorkStatus.PENDING.name()))) .andExpect( MockMvcResultMatchers.jsonPath("$.works[0].works[0].type", Matchers.is(WorkType.TASK.name()))) .andExpect(MockMvcResultMatchers.jsonPath("$.works[1].name", Matchers.is(testWorkFlowTask1))) .andExpect(MockMvcResultMatchers.jsonPath("$.works[1].type", Matchers.is(WorkType.TASK.name()))) - .andExpect( - MockMvcResultMatchers.jsonPath("$.works[1].status", Matchers.is(WorkStatus.COMPLETED.name()))); + .andExpect(MockMvcResultMatchers.jsonPath("$.works[1].status", + Matchers.is(ParodosWorkStatus.COMPLETED.name()))); // then Mockito.verify(this.workFlowService, Mockito.times(1)).getWorkFlowStatus(masterWorkFlowExecutionId); diff --git a/workflow-service/src/test/java/com/redhat/parodos/workflow/execution/service/WorkFlowServiceDelegateTest.java b/workflow-service/src/test/java/com/redhat/parodos/workflow/execution/service/WorkFlowServiceDelegateTest.java index 35c540e02..41dccd439 100644 --- a/workflow-service/src/test/java/com/redhat/parodos/workflow/execution/service/WorkFlowServiceDelegateTest.java +++ b/workflow-service/src/test/java/com/redhat/parodos/workflow/execution/service/WorkFlowServiceDelegateTest.java @@ -6,8 +6,8 @@ import com.redhat.parodos.workflow.definition.repository.WorkFlowDefinitionRepository; import com.redhat.parodos.workflow.definition.repository.WorkFlowTaskDefinitionRepository; import com.redhat.parodos.workflow.definition.repository.WorkFlowWorkRepository; +import com.redhat.parodos.workflow.enums.ParodosWorkStatus; import com.redhat.parodos.workflow.enums.WorkFlowStatus; -import com.redhat.parodos.workflow.enums.WorkStatus; import com.redhat.parodos.workflow.enums.WorkType; import com.redhat.parodos.workflow.execution.dto.WorkStatusResponseDTO; import com.redhat.parodos.workflow.execution.entity.WorkFlowExecution; @@ -175,20 +175,20 @@ void testGetWorkFlowWorksStatus() { // sub workflow 1 assertEquals(workStatusResponseDTOs.get(0).getType(), WorkType.WORKFLOW); assertEquals(workStatusResponseDTOs.get(0).getName(), testSubWorkFlowDefinition1.getName()); - assertEquals(workStatusResponseDTOs.get(0).getStatus(), WorkStatus.PENDING); + assertEquals(workStatusResponseDTOs.get(0).getStatus(), ParodosWorkStatus.PENDING); assertEquals(workStatusResponseDTOs.get(0).getWorks().size(), 1); // sub workflow 1 task 1 assertEquals(workStatusResponseDTOs.get(0).getWorks().get(0).getType(), WorkType.TASK); assertEquals(workStatusResponseDTOs.get(0).getWorks().get(0).getName(), testSubWorkFlowTaskDefinition1.getName()); - assertEquals(workStatusResponseDTOs.get(0).getWorks().get(0).getStatus(), WorkStatus.PENDING); + assertEquals(workStatusResponseDTOs.get(0).getWorks().get(0).getStatus(), ParodosWorkStatus.PENDING); assertNull(workStatusResponseDTOs.get(0).getWorks().get(0).getWorks()); // workflow task 1 assertEquals(workStatusResponseDTOs.get(1).getType(), WorkType.TASK); assertEquals(workStatusResponseDTOs.get(1).getName(), testWorkFlowTaskDefinition1.getName()); - assertEquals(workStatusResponseDTOs.get(1).getStatus(), WorkStatus.COMPLETED); + assertEquals(workStatusResponseDTOs.get(1).getStatus(), ParodosWorkStatus.COMPLETED); assertNull(workStatusResponseDTOs.get(1).getWorks()); } diff --git a/workflow-service/src/test/java/com/redhat/parodos/workflow/execution/service/WorkFlowServiceImplTest.java b/workflow-service/src/test/java/com/redhat/parodos/workflow/execution/service/WorkFlowServiceImplTest.java index dd03ff08f..b317b4085 100644 --- a/workflow-service/src/test/java/com/redhat/parodos/workflow/execution/service/WorkFlowServiceImplTest.java +++ b/workflow-service/src/test/java/com/redhat/parodos/workflow/execution/service/WorkFlowServiceImplTest.java @@ -261,7 +261,7 @@ void testSaveWorkflow() { // when WorkFlowExecution res = this.workFlowService.saveWorkFlow(projectId, workflowDefID, WorkFlowStatus.COMPLETED, - masterWorkFlowExecution); + masterWorkFlowExecution, "{}"); // then assertNotNull(res); @@ -505,13 +505,13 @@ void testGetWorkFlowStatusWithValidData() { Mockito.eq(workFlowDefinition))) .thenReturn(List.of( WorkStatusResponseDTO.builder().name(SUB_WORKFLOW_1_NAME).type(WorkType.WORKFLOW) - .status(com.redhat.parodos.workflow.enums.WorkStatus.PENDING) + .status(com.redhat.parodos.workflow.enums.ParodosWorkStatus.PENDING) .works(List.of(WorkStatusResponseDTO.builder().name(SUB_WORKFLOW_1_TASK_1_NAME) .type(WorkType.TASK) - .status(com.redhat.parodos.workflow.enums.WorkStatus.PENDING).build())) + .status(com.redhat.parodos.workflow.enums.ParodosWorkStatus.PENDING).build())) .workExecution(subWorkFlow1Execution).numberOfWorks(1).build(), WorkStatusResponseDTO.builder().name(WORKFLOW_TASK_1_NAME).type(WorkType.TASK) - .status(com.redhat.parodos.workflow.enums.WorkStatus.COMPLETED).build())); + .status(com.redhat.parodos.workflow.enums.ParodosWorkStatus.COMPLETED).build())); // then WorkFlowStatusResponseDTO workFlowStatusResponseDTO = this.workFlowService .getWorkFlowStatus(workFlowExecutionId); @@ -691,10 +691,10 @@ void testGetWorkFlowStatusWhenSubWorkflowNotExecutedWithValidData() { Mockito.eq(workFlowDefinition))) .thenReturn(List.of( WorkStatusResponseDTO.builder().name(SUB_WORKFLOW_1_NAME).type(WorkType.WORKFLOW) - .status(com.redhat.parodos.workflow.enums.WorkStatus.PENDING) + .status(com.redhat.parodos.workflow.enums.ParodosWorkStatus.PENDING) .works(Collections.emptyList()).numberOfWorks(1).build(), WorkStatusResponseDTO.builder().name(WORKFLOW_TASK_1_NAME).type(WorkType.TASK) - .status(com.redhat.parodos.workflow.enums.WorkStatus.COMPLETED).build())); + .status(com.redhat.parodos.workflow.enums.ParodosWorkStatus.COMPLETED).build())); // then WorkFlowStatusResponseDTO workFlowStatusResponseDTO = this.workFlowService @@ -717,7 +717,7 @@ void testGetWorkFlowStatusWhenSubWorkflowNotExecutedWithValidData() { assertEquals(workFlowStatusResponseDTO.getWorks().get(1).getType(), WorkType.TASK); assertEquals(workFlowStatusResponseDTO.getWorks().get(1).getName(), workFlowTask1Definition.getName()); assertEquals(workFlowStatusResponseDTO.getWorks().get(1).getStatus().name(), - com.redhat.parodos.workflow.enums.WorkStatus.COMPLETED.name()); + com.redhat.parodos.workflow.enums.ParodosWorkStatus.COMPLETED.name()); assertNull(workFlowStatusResponseDTO.getWorks().get(1).getWorks()); }