private void returnCanceledRunToQueue(ExecutionState executionStateToCancel) { // set the context and return the run to the queue. It will be handled on "finishFlow" // (QueueEventListener). Execution executionObj = executionSerializationUtil.objFromBytes(executionStateToCancel.getExecutionObject()); if (executionObj == null) { logger.error( "Run Object is null. Execution Id = " + executionStateToCancel.getExecutionId() + "; Branch Id = " + executionStateToCancel.getBranchId()); return; } executionObj.getSystemContext().setFlowTerminationType(ExecutionStatus.CANCELED); executionObj.setPosition(null); // just in case - we shouldn't need it, because the Execution is back to the queue as // "Terminated" executionStateToCancel.setStatus(ExecutionStatus.PENDING_CANCEL); // clean the DB field executionStateToCancel.setExecutionObject(null); // return execution to queue, as "Terminated" queueDispatcherService.dispatch( String.valueOf(executionObj.getExecutionId()), executionObj.getGroupName(), ExecStatus.TERMINATED, executionMessageConverter.createPayload(executionObj)); }
private ExecutionState createExecutionState(ExecutionStatus status) { ExecutionState executionState = new ExecutionState(); executionState.setStatus(status); executionState.setExecutionId(123L); executionState.setBranchId(UUID.randomUUID().toString()); executionStateRepository.saveAndFlush(executionState); return executionState; }
@Test public void testFindExecutionIdByStatuses() { ExecutionState canceledExecutionState = createExecutionState(ExecutionStatus.CANCELED); ExecutionState completedExecutionState = createExecutionState(ExecutionStatus.COMPLETED); createExecutionState(ExecutionStatus.PENDING_CANCEL); List<Long> executionStates = executionStateRepository.findExecutionIdByStatuses( Arrays.asList(ExecutionStatus.CANCELED, ExecutionStatus.COMPLETED)); assertThat(executionStates) .containsExactly( canceledExecutionState.getExecutionId(), completedExecutionState.getExecutionId()); }
@Override @Transactional public ExecutionActionResult requestCancelExecution(Long executionId) { if (logger.isDebugEnabled()) { logger.debug("Cancelling Execution Id: " + executionId); } if (executionId == null) { throw new IllegalArgumentException( "Null is not allowed as input of execution id in cancelExecution()"); } ExecutionState executionStateToCancel = executionStateService.readByExecutionIdAndBranchId(executionId, EMPTY_BRANCH); // we must have such execution in the table - the record is created on execution triggering if (executionStateToCancel == null) { String errMsg = "Failed to cancel execution. Execution id: " + executionId + "."; logger.error(errMsg); return ExecutionActionResult.FAILED_NOT_FOUND; } ExecutionStatus status = executionStateToCancel.getStatus(); if (status.equals(ExecutionStatus.CANCELED) || status.equals(ExecutionStatus.PENDING_CANCEL)) { return ExecutionActionResult.FAILED_ALREADY_CANCELED_OR_PENDING_CANCELLATION; } // it's possible to cancel only running or paused executions. // If it's running - set to pending-cancel, and the ExecutionServiceImpl will handle it and // extract it from the queue. // If it's paused - sometimes needs to handle its branches (if such exists). if (status.equals(ExecutionStatus.RUNNING)) { executionStateToCancel.setStatus(ExecutionStatus.PENDING_CANCEL); } else if (status.equals(ExecutionStatus.PAUSED)) { cancelPausedRun(executionStateToCancel); } else { String errMsg = "Failed to cancel execution. Execution id: " + executionId + ". Execution is in status: " + executionStateToCancel.getStatus().name(); logger.error(errMsg); return ExecutionActionResult.getExecutionActionResult(status); } return ExecutionActionResult.SUCCESS; }
// Cancel paused run according to its branches state // If the run has branches, (it can be branch-paused / user-paused / no-workers-in-group) - // then it's a 'virtual' pause, and we should cancel the paused branches. Then, the run itself // will be canceled as well. // If it doesn't - just cancel it straight away - extract the Run Object, set its context // accordingly and put into the queue. private void cancelPausedRun(ExecutionState executionStateToCancel) { final List<ExecutionState> branches = executionStateService.readByExecutionId(executionStateToCancel.getExecutionId()); // If the parent is paused because one of the branches is paused, OR, it was paused by the user // / no-workers-in-group, but has branches that were not finished (and thus, were paused) - // The parent itself will return to the queue after all the branches are ended (due to this // cancellation), and then it'll be canceled as well. if (branches.size() > 1) { // more than 1 means that it has paused branches (branches is at least 1 - the // parent) for (ExecutionState branch : branches) { if (!EMPTY_BRANCH.equals(branch.getBranchId())) { // exclude the base execution returnCanceledRunToQueue(branch); executionStateService.deleteExecutionState(branch.getExecutionId(), branch.getBranchId()); } } executionStateToCancel.setStatus( ExecutionStatus .PENDING_CANCEL); // when the parent will return to queue - should have the correct // status } else { returnCanceledRunToQueue(executionStateToCancel); } }