public WorkflowModel terminateWorkflow(
            WorkflowModel workflow, String reason, String failureWorkflow) {
        try {
            executionLockService.acquireLock(workflow.getWorkflowId(), 60000);

            if (!workflow.getStatus().isTerminal()) {
                workflow.setStatus(WorkflowModel.Status.TERMINATED);
            }

            try {
                deciderService.updateWorkflowOutput(workflow, null);
            } catch (Exception e) {
                // catch any failure in this step and continue the execution of terminating workflow
                LOGGER.error(
                        "Failed to update output data for workflow: {}",
                        workflow.getWorkflowId(),
                        e);
                Monitors.error(CLASS_NAME, "terminateWorkflow");
            }

            // update the failed reference task names
            List<TaskModel> failedTasks =
                    workflow.getTasks().stream()
                            .filter(
                                    t ->
                                            FAILED.equals(t.getStatus())
                                                    || FAILED_WITH_TERMINAL_ERROR.equals(
                                                            t.getStatus()))
                            .collect(Collectors.toList());

            workflow.getFailedReferenceTaskNames()
                    .addAll(
                            failedTasks.stream()
                                    .map(TaskModel::getReferenceTaskName)
                                    .collect(Collectors.toSet()));

            workflow.getFailedTaskNames()
                    .addAll(
                            failedTasks.stream()
                                    .map(TaskModel::getTaskDefName)
                                    .collect(Collectors.toSet()));

            String workflowId = workflow.getWorkflowId();
            workflow.setReasonForIncompletion(reason);
            executionDAOFacade.updateWorkflow(workflow);
            workflowStatusListener.onWorkflowTerminatedIfEnabled(workflow);
            Monitors.recordWorkflowTermination(
                    workflow.getWorkflowName(), workflow.getStatus(), workflow.getOwnerApp());
            LOGGER.info("Workflow {} is terminated because of {}", workflowId, reason);
            List<TaskModel> tasks = workflow.getTasks();
            try {
                // Remove from the task queue if they were there
                tasks.forEach(
                        task -> queueDAO.remove(QueueUtils.getQueueName(task), task.getTaskId()));
            } catch (Exception e) {
                LOGGER.warn(
                        "Error removing task(s) from queue during workflow termination : {}",
                        workflowId,
                        e);
            }

            if (workflow.hasParent()) {
                updateParentWorkflowTask(workflow);
                LOGGER.info(
                        "{} updated parent {} task {}",
                        workflow.toShortString(),
                        workflow.getParentWorkflowId(),
                        workflow.getParentWorkflowTaskId());
                expediteLazyWorkflowEvaluation(workflow.getParentWorkflowId());
            }

            if (!StringUtils.isBlank(failureWorkflow)) {
                Map<String, Object> input = new HashMap<>(workflow.getInput());
                input.put("workflowId", workflowId);
                input.put("reason", reason);
                input.put("failureStatus", workflow.getStatus().toString());
                if (workflow.getFailedTaskId() != null) {
                    input.put("failureTaskId", workflow.getFailedTaskId());
                }
                input.put("failedWorkflow", workflow);

                try {
                    String failureWFId = idGenerator.generate();
                    StartWorkflowInput startWorkflowInput = new StartWorkflowInput();
                    startWorkflowInput.setName(failureWorkflow);
                    startWorkflowInput.setWorkflowInput(input);
                    startWorkflowInput.setCorrelationId(workflow.getCorrelationId());
                    startWorkflowInput.setTaskToDomain(workflow.getTaskToDomain());
                    startWorkflowInput.setWorkflowId(failureWFId);
                    startWorkflowInput.setTriggeringWorkflowId(workflowId);

                    eventPublisher.publishEvent(new WorkflowCreationEvent(startWorkflowInput));

                    workflow.addOutput("conductor.failure_workflow", failureWFId);
                } catch (Exception e) {
                    LOGGER.error("Failed to start error workflow", e);
                    workflow.getOutput()
                            .put(
                                    "conductor.failure_workflow",
                                    "Error workflow "
                                            + failureWorkflow
                                            + " failed to start.  reason: "
                                            + e.getMessage());
                    Monitors.recordWorkflowStartError(
                            failureWorkflow, WorkflowContext.get().getClientApp());
                }
                executionDAOFacade.updateWorkflow(workflow);
            }
            executionDAOFacade.removeFromPendingWorkflow(
                    workflow.getWorkflowName(), workflow.getWorkflowId());

            List<String> erroredTasks = cancelNonTerminalTasks(workflow);
            if (!erroredTasks.isEmpty()) {
                throw new NonTransientException(
                        String.format(
                                "Error canceling system tasks: %s",
                                String.join(",", erroredTasks)));
            }
            return workflow;
        } finally {
            executionLockService.releaseLock(workflow.getWorkflowId());
            executionLockService.deleteLock(workflow.getWorkflowId());
        }
    }
@param workflow the workflow to be terminated
@param reason the reason for termination
@param failureWorkflow the failure workflow (if any) to be triggered as a result of this
    termination
core/src/main/java/com/netflix/conductor/core/execution/WorkflowExecutor.java