Refactoring to enable on_failure for imperative workflow
[ccsdk/cds.git] / ms / blueprintsprocessor / modules / services / workflow-service / src / main / kotlin / org / onap / ccsdk / cds / blueprintsprocessor / services / workflow / ImperativeWorkflowExecutionService.kt
index 2278dbf..29019b7 100644 (file)
@@ -23,6 +23,7 @@ import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceOutp
 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.Status
 import org.onap.ccsdk.cds.controllerblueprints.common.api.EventType
 import org.onap.ccsdk.cds.controllerblueprints.core.BlueprintConstants
+import org.onap.ccsdk.cds.controllerblueprints.core.BlueprintException
 import org.onap.ccsdk.cds.controllerblueprints.core.BlueprintProcessorException
 import org.onap.ccsdk.cds.controllerblueprints.core.MDCContext
 import org.onap.ccsdk.cds.controllerblueprints.core.asGraph
@@ -30,6 +31,7 @@ import org.onap.ccsdk.cds.controllerblueprints.core.checkNotEmpty
 import org.onap.ccsdk.cds.controllerblueprints.core.data.EdgeLabel
 import org.onap.ccsdk.cds.controllerblueprints.core.data.Graph
 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BlueprintWorkflowExecutionService
+import org.onap.ccsdk.cds.controllerblueprints.core.isAcyclic
 import org.onap.ccsdk.cds.controllerblueprints.core.logger
 import org.onap.ccsdk.cds.controllerblueprints.core.service.AbstractBlueprintWorkFlowService
 import org.onap.ccsdk.cds.controllerblueprints.core.service.BlueprintRuntimeService
@@ -57,6 +59,10 @@ class ImperativeWorkflowExecutionService(
 
         val graph = bluePrintContext.workflowByName(workflowName).asGraph()
 
+        if (!graph.isAcyclic()) {
+            throw BlueprintException("Imperative workflow must be acyclic. Check on_success/on_failure for circular references")
+        }
+
         return coroutineScope {
             ImperativeBlueprintWorkflowService(
                 nodeTemplateExecutionService,
@@ -108,7 +114,7 @@ open class ImperativeBlueprintWorkflowService(private val nodeTemplateExecutionS
             if (exceptions.isNotEmpty()) {
                 exceptions.forEach {
                     val errorMessage = it.message ?: ""
-                    bluePrintRuntimeService.getBlueprintError().addError(errorMessage)
+                    bluePrintRuntimeService.getBlueprintError().addError(errorMessage, "workflow")
                     log.error("workflow($workflowId) exception :", it)
                 }
                 message = BlueprintConstants.STATUS_FAILURE
@@ -154,12 +160,15 @@ open class ImperativeBlueprintWorkflowService(private val nodeTemplateExecutionS
 
         /** execute node template */
         val executionServiceOutput = nodeTemplateExecutionService
-            .executeNodeTemplate(bluePrintRuntimeService, nodeTemplateName, nodeInput)
+            .executeNodeTemplate(bluePrintRuntimeService, node.id, nodeTemplateName, nodeInput)
 
-        return when (executionServiceOutput.status.message) {
-            BlueprintConstants.STATUS_FAILURE -> EdgeLabel.FAILURE
-            else -> EdgeLabel.SUCCESS
+        if (executionServiceOutput.status.message == BlueprintConstants.STATUS_FAILURE) {
+            // Clear step errors so that the workflow does not fail
+            bluePrintRuntimeService.getBlueprintError().stepErrors(node.id)?.clear()
+            return EdgeLabel.FAILURE
         }
+
+        return EdgeLabel.SUCCESS
     }
 
     override suspend fun skipNode(