public override void Execute(IExecutionEntity execution) { // The join in the inclusive gateway works as follows: // When an execution enters it, it is inactivated. // All the inactivated executions stay in the inclusive gateway // until ALL executions that CAN reach the inclusive gateway have reached it. // // This check is repeated on execution changes until the inactivated // executions leave the gateway. execution.Inactivate(); ExecuteInclusiveGatewayLogic(execution); }
public override void Leave(IExecutionEntity execution, object signalData) { lock (syncRoot) { ICommandContext commandContext = Context.CommandContext; if (commandContext == null) { throw new ActivitiException("lazy loading outside command context"); } completedPolicy.LeaveExection = execution; bool zeroNrOfInstances = false; if (ResolveNrOfInstances(execution) == 0) { // Empty collection, just leave. zeroNrOfInstances = true; RemoveLocalLoopVariable(execution, CollectionElementIndexVariable); base.Leave(execution, signalData); // Plan the default leave execution.IsMultiInstanceRoot = false; } int loopCounter = GetLoopVariable(execution, CollectionElementIndexVariable).GetValueOrDefault(0); int nrOfInstances = GetLoopVariable(execution, NUMBER_OF_INSTANCES).GetValueOrDefault(0); int nrOfCompletedInstances = GetLoopVariable(execution, NUMBER_OF_COMPLETED_INSTANCES).GetValueOrDefault(0) + 1; int nrOfActiveInstances = GetLoopVariable(execution, NUMBER_OF_ACTIVE_INSTANCES).GetValueOrDefault(0) - 1; Context.CommandContext.HistoryManager.RecordActivityEnd(execution, null); CallActivityEndListeners(execution); if (zeroNrOfInstances) { return; } IExecutionEntity miRootExecution = GetMultiInstanceRootExecution(execution); if (miRootExecution != null) { // will be null in case of empty collection SetLoopVariable(miRootExecution, NUMBER_OF_COMPLETED_INSTANCES, nrOfCompletedInstances); SetLoopVariable(miRootExecution, NUMBER_OF_ACTIVE_INSTANCES, nrOfActiveInstances < 0 ? 0 : nrOfActiveInstances); } //ExecuteCompensationBoundaryEvents(execution.CurrentFlowElement, execution); LogLoopDetails(execution, "instance completed", loopCounter, nrOfCompletedInstances, nrOfActiveInstances, nrOfActiveInstances < 0 ? 0 : nrOfActiveInstances); if (execution.Parent != null) { execution.Inactivate(); LockFirstParentScope(execution); if (CompletionConditionSatisfied(execution.Parent, signalData) || nrOfCompletedInstances >= nrOfInstances) { IExecutionEntity executionToUse; if (nrOfInstances > 0) { executionToUse = execution.Parent; } else { executionToUse = execution; } bool hasCompensation = false; Activity activity = (Activity)execution.CurrentFlowElement; if (activity is Transaction) { hasCompensation = true; } else if (activity is SubProcess subProcess) { foreach (FlowElement subElement in subProcess.FlowElements) { if (subElement is Activity subActivity) { if (CollectionUtil.IsNotEmpty(subActivity.BoundaryEvents)) { foreach (BoundaryEvent boundaryEvent in subActivity.BoundaryEvents) { if (CollectionUtil.IsNotEmpty(boundaryEvent.EventDefinitions) && boundaryEvent.EventDefinitions[0] is CompensateEventDefinition) { hasCompensation = true; break; } } } } } } if (hasCompensation) { ScopeUtil.CreateCopyOfSubProcessExecutionForCompensation(executionToUse); } if (activity is CallActivity) { IExecutionEntityManager executionEntityManager = Context.CommandContext.ExecutionEntityManager; if (executionToUse != null) { IList <string> callActivityExecutionIds = new List <string>(); // Find all execution entities that are at the call activity IList <IExecutionEntity> childExecutions = executionEntityManager.CollectChildren(executionToUse); if (childExecutions != null) { foreach (IExecutionEntity childExecution in childExecutions) { if (activity.Id.Equals(childExecution.CurrentActivityId)) { callActivityExecutionIds.Add(childExecution.Id); } } // Now all call activity executions have been collected, loop again and check which should be removed for (int i = childExecutions.Count - 1; i >= 0; i--) { IExecutionEntity childExecution = childExecutions[i]; if (!string.IsNullOrWhiteSpace(childExecution.SuperExecutionId) && callActivityExecutionIds.Contains(childExecution.SuperExecutionId)) { executionEntityManager.DeleteProcessInstanceExecutionEntity(childExecution.Id, activity.Id, "call activity completion condition met", true, false); } } } } } DeleteChildExecutions(executionToUse, false, Context.CommandContext); RemoveLocalLoopVariable(executionToUse, CollectionElementIndexVariable); executionToUse.IsScope = false; executionToUse.IsMultiInstanceRoot = false; Context.Agenda.PlanTakeOutgoingSequenceFlowsOperation(executionToUse, true); } } else { RemoveLocalLoopVariable(execution, CollectionElementIndexVariable); execution.IsMultiInstanceRoot = false; base.Leave(execution, signalData); } } }
public override void Execute(IExecutionEntity execution) { // First off all, deactivate the execution execution.Inactivate(); // Join FlowElement flowElement = execution.CurrentFlowElement; ParallelGateway parallelGateway; if (flowElement is ParallelGateway) { parallelGateway = (ParallelGateway)flowElement; } else { throw new ActivitiException("Programmatic error: parallel gateway behaviour can only be applied" + " to a ParallelGateway instance, but got an instance of " + flowElement); } LockFirstParentScope(execution); IExecutionEntity multiInstanceExecution = null; if (HasMultiInstanceParent(parallelGateway)) { multiInstanceExecution = FindMultiInstanceParentExecution(execution); } IExecutionEntityManager executionEntityManager = Context.CommandContext.ExecutionEntityManager; ICollection <IExecutionEntity> joinedExecutions = executionEntityManager.FindInactiveExecutionsByActivityIdAndProcessInstanceId(execution.CurrentActivityId, execution.ProcessInstanceId); if (multiInstanceExecution != null) { joinedExecutions = CleanJoinedExecutions(joinedExecutions, multiInstanceExecution); } int nbrOfExecutionsToJoin = parallelGateway.IncomingFlows.Count; int nbrOfExecutionsCurrentlyJoined = joinedExecutions.Count; // Fork // Is needed to set the endTime for all historic activity joins Context.CommandContext.HistoryManager.RecordActivityEnd(execution, null); if (nbrOfExecutionsCurrentlyJoined == nbrOfExecutionsToJoin) { // Fork if (log.IsEnabled(LogLevel.Debug)) { log.LogDebug($"parallel gateway '{execution.CurrentActivityId}' activates: {nbrOfExecutionsCurrentlyJoined} of {nbrOfExecutionsToJoin} joined"); } if (parallelGateway.IncomingFlows.Count > 1) { // All (now inactive) children are deleted. foreach (IExecutionEntity joinedExecution in joinedExecutions) { // The current execution will be reused and not deleted if (!joinedExecution.Id.Equals(execution.Id)) { executionEntityManager.DeleteExecutionAndRelatedData(joinedExecution, null, false); } } } // TODO: potential optimization here: reuse more then 1 execution, only 1 currently Context.Agenda.PlanTakeOutgoingSequenceFlowsOperation(execution, false); // false -> ignoring conditions on parallel gw } else if (log.IsEnabled(LogLevel.Debug)) { log.LogDebug($"parallel gateway '{execution.CurrentActivityId}' does not activate: {nbrOfExecutionsCurrentlyJoined} of {nbrOfExecutionsToJoin} joined"); } }