Skip to content

Commit

Permalink
Refactor child workflow saving to work via StateExecution
Browse files Browse the repository at this point in the history
  • Loading branch information
jsyrjala committed May 6, 2015
1 parent 8a20b83 commit 732c85b
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,10 @@ private void runImpl() {
rescheduleUnknownWorkflowState(instance);
return;
}
NextAction nextAction = null;

try {
processBeforeListeners(listenerContext);
nextAction = processState(instance, definition, execution, state);
NextAction nextAction = processState(instance, definition, execution, state);
if (listenerContext != null) {
listenerContext.nextAction = nextAction;
}
Expand All @@ -127,7 +127,7 @@ private void runImpl() {
processAfterListeners(listenerContext);
}
subsequentStateExecutions = busyLoopPrevention(settings, subsequentStateExecutions, execution);
instance = saveWorkflowInstanceState(execution, instance, definition, nextAction, actionBuilder);
instance = saveWorkflowInstanceState(execution, instance, definition, actionBuilder);
}
}
logger.debug("Finished.");
Expand Down Expand Up @@ -174,7 +174,7 @@ private int busyLoopPrevention(WorkflowSettings settings,
}

private WorkflowInstance saveWorkflowInstanceState(StateExecutionImpl execution, WorkflowInstance instance,
WorkflowDefinition<?> definition, NextAction nextAction, WorkflowInstanceAction.Builder actionBuilder) {
WorkflowDefinition<?> definition, WorkflowInstanceAction.Builder actionBuilder) {
if (definition.getMethod(execution.getNextState()) == null && execution.getNextActivation() != null) {
logger.info("No handler method defined for {}, clearing next activation", execution.getNextState());
execution.setNextActivation(null);
Expand All @@ -187,9 +187,8 @@ private WorkflowInstance saveWorkflowInstanceState(StateExecutionImpl execution,
.setRetries(execution.isRetry() ? execution.getRetries() + 1 : 0);
actionBuilder.setExecutionEnd(now()).setType(getActionType(execution)).setStateText(execution.getNextStateReason());

// TODO this null check is due to lazy test writer
List<WorkflowInstance> childWorkflows = nextAction != null ? nextAction.getChildWorkflows() : Arrays.<WorkflowInstance>asList();
workflowInstanceDao.updateWorkflowInstanceAfterExecution(builder.build(), actionBuilder.build(), childWorkflows);
workflowInstanceDao.updateWorkflowInstanceAfterExecution(builder.build(), actionBuilder.build(),
execution.getNewChildWorkflows());
return builder.setOriginalStateVariables(instance.stateVariables).build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import com.nitorcreations.nflow.engine.workflow.definition.WorkflowState;
import com.nitorcreations.nflow.engine.workflow.instance.WorkflowInstance;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

public class StateExecutionImpl implements StateExecution {
Expand All @@ -23,6 +25,7 @@ public class StateExecutionImpl implements StateExecution {
private Throwable thrown;
private boolean isFailed;
private boolean isRetryCountExceeded;
private List<WorkflowInstance> newChildWorkflows = new LinkedList<>();

public StateExecutionImpl(WorkflowInstance instance, ObjectStringMapper objectMapper, WorkflowInstanceDao workflowDao) {
this.instance = instance;
Expand Down Expand Up @@ -141,9 +144,21 @@ public void setRetryCountExceeded() {
isRetryCountExceeded = true;
}

public void addChildWorkflows(WorkflowInstance ... childWorkflows) {
Assert.notNull(childWorkflows, "childWorkflows can not be null");
for(WorkflowInstance child : childWorkflows) {
Assert.notNull(child, "childWorkflow can not be null");
newChildWorkflows.add(child);
}
}

public List<WorkflowInstance> getNewChildWorkflows() {
return Collections.unmodifiableList(newChildWorkflows);
}

// TODO add tests
@Override
public List<WorkflowInstance> getChildWorkflows(QueryWorkflowInstances query) {
public List<WorkflowInstance> queryChildWorkflows(QueryWorkflowInstances query) {
QueryWorkflowInstances restrictedQuery = new QueryWorkflowInstances.Builder(query)
.setParentWorkflowId(instance.id).build();
return workflowDao.queryWorkflowInstances(restrictedQuery);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,20 @@

import static org.joda.time.DateTime.now;

import com.nitorcreations.nflow.engine.workflow.instance.WorkflowInstance;
import org.joda.time.DateTime;

import com.nitorcreations.nflow.engine.internal.executor.InvalidNextActionException;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class NextAction {

private final DateTime activation;
private final WorkflowState nextState;
private final String reason;
private final List<WorkflowInstance> childWorkflows;

private NextAction(DateTime activation, WorkflowState nextState, String reason) {
this(activation, nextState, Arrays.<WorkflowInstance>asList(), reason);
}

private NextAction(DateTime activation, WorkflowState nextState,
List<WorkflowInstance> childWorkflows, String reason) {
this.reason = reason;
this.nextState = nextState;
this.activation = activation;
this.childWorkflows = Collections.unmodifiableList(childWorkflows);
}

/**
Expand Down Expand Up @@ -79,22 +67,6 @@ public static NextAction moveToStateAfter(WorkflowState nextState, DateTime acti
return new NextAction(activation, nextState, reason);
}

/**
* Schedule processing of state {@code nextState} at time {@code activation}.
* @param nextState The next workflow state.
* @param activation The time after which the workflow can be activated.
* @param childWorkflows list of child workflows to create.
* @param reason The reason for the action.
* @return A valid {@code NextAction} value.
*/
public static NextAction moveToStateAfter(WorkflowState nextState, DateTime activation,
List<WorkflowInstance> childWorkflows, String reason) {
assertNotNull(nextState, "Next state can not be null");
assertNotNull(activation, "Activation can not be null");
assertNotNull(childWorkflows, "childWorkflows can not be null");
return new NextAction(activation, nextState, childWorkflows, reason);
}

/**
* Schedule processing of state {@code nextState} immediately.
* @param nextState The next workflow state.
Expand All @@ -106,19 +78,6 @@ public static NextAction moveToState(WorkflowState nextState, String reason) {
return new NextAction(now(), nextState, reason);
}

/**
* Schedule processing of state {@code nextState} immediately.
* @param nextState The next workflow state.
* @param childWorkflows list of child workflows to create.
* @param reason The reason for the action.
* @return A valid {@code NextAction} value.
*/
public static NextAction moveToState(WorkflowState nextState, List<WorkflowInstance> childWorkflows, String reason) {
assertNotNull(nextState, "Next state can not be null");
assertNotNull(childWorkflows, "childWorkflows can not be null");
return new NextAction(now(), nextState, childWorkflows, reason);
}

/**
* Set next state to {@code finalState} and do not schedule its
* processing. The {@code finalState} workflow state type must
Expand Down Expand Up @@ -158,12 +117,4 @@ public boolean isRetry() {
return nextState == null;
}

/**
* Return list of child workflows.
* @return list of child workflows.
*/
public List<WorkflowInstance> getChildWorkflows() {
return childWorkflows;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,19 @@ public interface StateExecution {
*/
String getWorkflowInstanceExternalId();

/**
* Add a new child workflow. Child workflows are stored to database scheduled after current
* state method exists successfully.
* Note that Child workflows are not visible to queryChildWorkflows() method before they are stored to database.
* @param childWorkflows
*/
void addChildWorkflows(WorkflowInstance ... childWorkflows);

/**
* Return child workflow instances for current workflow. Query is restricted to childs of current workflow.
* @param query The query criterias.
* @return List of child workflows that match the query.
*/
List<WorkflowInstance> getChildWorkflows(QueryWorkflowInstances query);
List<WorkflowInstance> queryChildWorkflows(QueryWorkflowInstances query);

}
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ private NextAction nextStep(StateExecution execution, int nextN, int offset, Sta

execution.setVariable("childrenCount", String.valueOf(getChildrenCount(execution) + 1));
logger.info("Create child workflow N={}", nextN);
List<WorkflowInstance> childWorkflows = Arrays.asList(createWorkflow(nextN));
return NextAction.moveToState(nextState, childWorkflows, "Creating childWorkflow to process f(" + nextN + ")");
execution.addChildWorkflows(createWorkflow(nextN));
return NextAction.moveToState(nextState, "Creating childWorkflow to process f(" + nextN + ")");
}

private int getChildrenCount(StateExecution execution) {
Expand All @@ -100,7 +100,7 @@ private int getChildrenCount(StateExecution execution) {

public NextAction poll(StateExecution execution, @StateVar(value="requestData") int n) {
// get finished and failed child workflows
List<WorkflowInstance> children = execution.getChildWorkflows(new QueryWorkflowInstances.Builder()
List<WorkflowInstance> children = execution.queryChildWorkflows(new QueryWorkflowInstances.Builder()
.addStatuses(manual.getStatus(), end.getStatus()).build());
if(children.size() < getChildrenCount(execution)) {
int delay = new Random().nextInt(5) + 1;
Expand Down

0 comments on commit 732c85b

Please sign in to comment.