All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.nflow.tests.demo.workflow.FibonacciWorkflow Maven / Gradle / Ivy

The newest version!
package io.nflow.tests.demo.workflow;

import static io.nflow.engine.workflow.definition.NextAction.moveToState;
import static io.nflow.engine.workflow.definition.NextAction.retryAfter;
import static io.nflow.engine.workflow.definition.NextAction.stopInState;
import static io.nflow.tests.demo.workflow.TestState.BEGIN;
import static io.nflow.tests.demo.workflow.TestState.DONE;
import static io.nflow.tests.demo.workflow.TestState.ERROR;
import static io.nflow.tests.demo.workflow.TestState.POLL;
import static java.lang.Integer.parseInt;
import static org.joda.time.DateTime.now;
import static org.slf4j.LoggerFactory.getLogger;

import java.util.List;

import org.slf4j.Logger;

import io.nflow.engine.workflow.curated.State;
import io.nflow.engine.workflow.definition.NextAction;
import io.nflow.engine.workflow.definition.StateExecution;
import io.nflow.engine.workflow.definition.StateVar;
import io.nflow.engine.workflow.definition.WorkflowDefinition;
import io.nflow.engine.workflow.definition.WorkflowState;
import io.nflow.engine.workflow.instance.QueryWorkflowInstances;
import io.nflow.engine.workflow.instance.WorkflowInstance;
import io.nflow.engine.workflow.instance.WorkflowInstance.WorkflowInstanceStatus;

/**
 * Fibonacci series generator using recursive process. Each step is handled by a new child workflow.
 */
public class FibonacciWorkflow extends WorkflowDefinition {
  public static final String FIBONACCI_TYPE = "fibonacci";
  public static final String VAR_REQUEST_DATA = "requestData";
  private static final Logger logger = getLogger(FibonacciWorkflow.class);

  private static final WorkflowState N_MINUS_1 = new State("nMinus1");
  private static final WorkflowState N_MINUS_2 = new State("nMinus2");

  @SuppressWarnings("this-escape")
  public FibonacciWorkflow() {
    super(FIBONACCI_TYPE, BEGIN, ERROR);
    setDescription("Fibonacci series generator using recursive process. Each step is handled by a new child workflow.");
    permit(BEGIN, N_MINUS_2);
    permit(N_MINUS_2, N_MINUS_1);
    permit(N_MINUS_2, POLL);
    permit(N_MINUS_1, POLL);
    permit(N_MINUS_1, DONE);
    permit(N_MINUS_2, DONE);
    permit(POLL, DONE);
  }

  public NextAction begin(StateExecution execution, @StateVar(value = VAR_REQUEST_DATA, readOnly = true) FiboData fiboData) {
    int n = fiboData.n;
    logger.info("Fibonacci step N = {}", n);
    execution.setVariable("result", 0);
    return moveToState(N_MINUS_2, "Starting N = " + n);
  }

  public NextAction nMinus2(StateExecution execution, @StateVar(value = VAR_REQUEST_DATA, readOnly = true) FiboData fiboData) {
    int n = fiboData.n;
    return nextStep(execution, n - 2, 2, N_MINUS_1);
  }

  public NextAction nMinus1(StateExecution execution, @StateVar(value = VAR_REQUEST_DATA, readOnly = true) FiboData fiboData) {
    int n = fiboData.n;
    return nextStep(execution, n - 1, 1, POLL);
  }

  private NextAction nextStep(StateExecution execution, int nextN, int offset, WorkflowState nextState) {
    if (nextN < 2) {
      logger.info("nextN = {}. skipping to done", nextN);
      execution.setVariable("result", execution.getVariable("result", Integer.class) + 1);
      return moveToState(nextState, "N - " + offset + " = " + nextN + ". Going to end.");
    }
    logger.info("Create child workflow N={}", nextN);
    execution.addChildWorkflows(createWorkflow(execution, nextN));
    return moveToState(nextState, "Creating childWorkflow to process f(" + nextN + ")");
  }

  public NextAction poll(StateExecution execution) {
    // get finished and failed child workflows
    QueryWorkflowInstances query = new QueryWorkflowInstances.Builder().addStatuses(WorkflowInstanceStatus.manual,
        WorkflowInstanceStatus.finished).setIncludeCurrentStateVariables(true).build();
    List finishedChildren = execution.queryChildWorkflows(query);

    if (finishedChildren.size() < execution.getAllChildWorkflows().size()) {
      return retryAfter(now().plusSeconds(10), "Child workflows are not ready yet.");
    }
    int sum = 0;
    for (WorkflowInstance child : finishedChildren) {
      if (child.status != WorkflowInstanceStatus.finished) {
        return stopInState(ERROR, "Some of the children failed");
      }
      String childResult = child.stateVariables.get("result");
      sum += parseInt(childResult != null ? childResult : "0");
    }
    execution.setVariable("result", execution.getVariable("result", Integer.class) + sum);
    return moveToState(DONE, "All is good");
  }

  public void done(@SuppressWarnings("unused") StateExecution execution, @StateVar(value = VAR_REQUEST_DATA) FiboData fiboData,
      @StateVar(value = "result") int result) {
    logger.info("We are done: fibonacci({}) == {}", fiboData.n, result);
  }

  public void error(@SuppressWarnings("unused") StateExecution execution, @StateVar(value = VAR_REQUEST_DATA) FiboData fiboData,
      @SuppressWarnings("unused") @StateVar(value = "result") int result) {
    logger.error("Failed to compute F({})", fiboData.n);
  }

  private WorkflowInstance createWorkflow(StateExecution execution, int n) {
    return execution.workflowInstanceBuilder().setType(FibonacciWorkflow.FIBONACCI_TYPE)
        .putStateVariable(VAR_REQUEST_DATA, new FiboData(n)).build();
  }

  public static class FiboData {
    public int n;

    public FiboData() {
      // for Jackson
    }

    public FiboData(int n) {
      this();
      this.n = n;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy