Skip to content

Commit

Permalink
obey maxRetries when NextAction.retryAfter(...) is used
Browse files Browse the repository at this point in the history
  • Loading branch information
Edvard Fonsell committed Sep 26, 2014
1 parent 9ef329b commit 0dc978c
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -162,14 +162,15 @@ private NextAction processState(WorkflowInstance instance, WorkflowDefinition<?>
execution.setFailed();
}
execution.setNextActivation(nextAction.getActivation());
execution.setNextStateReason(nextAction.getReason());
execution.setSaveTrace(nextAction.isSaveTrace());
if (nextAction.getNextState() == null) {
execution.setNextState(definition.getState(instance.state));
execution.setRetry(true);
definition.handleRetryAfter(execution, nextAction.getActivation());
} else {
execution.setNextState(nextAction.getNextState());
}
execution.setNextStateReason(nextAction.getReason());
execution.setSaveTrace(nextAction.isSaveTrace());
objectMapper.storeArguments(execution, method, args);
return nextAction;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static com.nitorcreations.nflow.engine.workflow.definition.WorkflowStateType.end;
import static com.nitorcreations.nflow.engine.workflow.definition.WorkflowStateType.manual;
import static java.lang.String.format;
import static org.joda.time.DateTime.now;

import java.util.ArrayList;
import java.util.LinkedHashMap;
Expand Down Expand Up @@ -187,26 +188,44 @@ void requireStateMethodExists(S state) {
* Handle retries for the state execution. The default implementation moves
* the workflow to a failure state after the maximum retry attempts is
* exceeded. If there is no failure state defined for the retried state, moves
* the workflow to the generic error state. If the maximum retry attempts is
* not exceeded, schedules the next attempt for the state based on workflow
* settings.
* the workflow to the generic error state and stops processing. Error state
* handler method, if it exists, is not executed. If the maximum retry attempts
* is not exceeded, schedules the next attempt for the state based on workflow
* settings. This method is called when an unexpected exception happens during
* state method handling.
* @param execution State execution information.
*/
public void handleRetry(StateExecutionImpl execution) {
handleRetryAfter(execution, getSettings().getErrorTransitionActivation(execution.getRetries()));
}

/**
* Handle retries for the state execution. The default implementation moves
* the workflow to a failure state after the maximum retry attempts is
* exceeded. If there is no failure state defined for the retried state, moves
* the workflow to the generic error state and stops processing. Error state
* handler method, if it exists, is not executed. If the maximum retry attempts
* is not exceeded, schedules the next attempt to the given activation time.
* This method is called when a retry attempt is explicitly requested by a
* state handling method.
* @param execution State execution information.
* @param activation Time for next retry attempt.
*/
public void handleRetryAfter(StateExecutionImpl execution, DateTime activation) {
if (execution.getRetries() >= getSettings().maxRetries) {
execution.setRetry(false);
WorkflowState failureState = failureTransitions.get(execution.getCurrentStateName());
if (failureState != null) {
execution.setNextState(failureState);
execution.setNextStateReason("Max retry count exceeded");
execution.setNextActivation(new DateTime());
execution.setNextActivation(now());
} else {
execution.setNextState(errorState);
execution.setNextStateReason("Max retry count exceeded, no failure state defined");
execution.setNextActivation(null);
}
} else {
execution.setNextActivation(getSettings().getErrorTransitionActivation(execution.getRetries()));
execution.setNextActivation(activation);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
import org.mockito.Mockito;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.nitorcreations.nflow.engine.internal.executor.WorkflowStateProcessor;
import com.nitorcreations.nflow.engine.internal.workflow.ObjectStringMapper;
import com.nitorcreations.nflow.engine.listener.WorkflowExecutorListener;
import com.nitorcreations.nflow.engine.listener.WorkflowExecutorListener.ListenerContext;
Expand Down Expand Up @@ -128,6 +127,22 @@ public void runWorkflowThroughToFailureState() {
assertThat(action.getAllValues().get(1), matchesWorkflowInstanceAction(FailingTestWorkflow.State.failure, 0));
}

@Test
public void maxRetryIsObeyedForManualRetry() {
WorkflowDefinition<FailingTestWorkflow.State> wf = new FailingTestWorkflow();
doReturn(wf).when(workflowDefinitions).getWorkflowDefinition(eq("test"));
WorkflowInstance instance = constructWorkflowInstanceBuilder()
.setType("test").setId(Integer.valueOf(1)).setProcessing(true)
.setState("retryingState").setRetries(wf.getSettings().maxRetries).build();
when(workflowInstances.getWorkflowInstance(instance.id)).thenReturn(instance);

executor.run();

verify(workflowInstances).updateWorkflowInstance(update.capture(), action.capture());
assertThat(update.getValue(), matchesWorkflowInstance(FailingTestWorkflow.State.error, 0, false, is(nullValue(DateTime.class))));
assertThat(action.getValue(), matchesWorkflowInstanceAction(FailingTestWorkflow.State.retryingState, wf.getSettings().maxRetries));
}

@Test
public void goToErrorStateWhenStateMethodReturnsNull() {
WorkflowDefinition<FailingTestWorkflow.State> wf = new FailingTestWorkflow();
Expand Down

0 comments on commit 0dc978c

Please sign in to comment.