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

brainslug.flow.execution.node.TaskNodeExecutor Maven / Gradle / Ivy

The newest version!
package brainslug.flow.execution.node;

import brainslug.flow.context.ExecutionContext;
import brainslug.flow.definition.DefinitionStore;
import brainslug.flow.execution.async.AsyncTrigger;
import brainslug.flow.execution.async.AsyncTriggerErrorDetails;
import brainslug.flow.execution.async.AsyncTriggerScheduler;
import brainslug.flow.execution.expression.ExpressionEvaluator;
import brainslug.flow.execution.node.task.CallDefinitionExecutor;
import brainslug.flow.execution.node.task.ScriptExecutor;
import brainslug.flow.expression.PredicateExpression;
import brainslug.flow.node.task.AbstractTaskDefinition;
import brainslug.flow.node.task.GoalDefinition;
import brainslug.flow.node.task.HandlerCallDefinition;
import brainslug.util.Option;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TaskNodeExecutor extends DefaultNodeExecutor> {

  private Logger log = LoggerFactory.getLogger(TaskNodeExecutor.class);

  DefinitionStore definitionStore;
  ExpressionEvaluator expressionEvaluator;
  CallDefinitionExecutor callDefinitionExecutor;
  AsyncTriggerScheduler asyncTriggerScheduler;
  ScriptExecutor scriptExecutor;

  public TaskNodeExecutor(DefinitionStore definitionStore,
                          ExpressionEvaluator expressionEvaluator,
                          CallDefinitionExecutor callDefinitionExecutor,
                          AsyncTriggerScheduler asyncTriggerScheduler,
                          ScriptExecutor scriptExecutor) {
    this.definitionStore = definitionStore;
    this.expressionEvaluator = expressionEvaluator;
    this.callDefinitionExecutor = callDefinitionExecutor;
    this.asyncTriggerScheduler = asyncTriggerScheduler;
    this.scriptExecutor = scriptExecutor;
  }

  @Override
  public FlowNodeExecutionResult execute(AbstractTaskDefinition taskDefinition, ExecutionContext execution) {
    if (taskDefinition.getGoal().isPresent() && goalIsFulfilled(taskDefinition.getGoal().get(), execution)) {
      return takeAllAndRemoveFirst(taskDefinition, execution.getInstance());
    } else if (taskDefinition.isAsync() && !execution.isAsync()) {
      scheduleAsyncTask(taskDefinition, execution);
      return takeNone(taskDefinition, execution.getInstance());
    } else if (isExecutable(taskDefinition)) {
      return executeWithOptionalAsyncRetry(taskDefinition, execution);
    } else {
      log.warn("executing task node without execution definition, " +
        "please specify the task node execution by using a delegate class or call definition to actually do something in this task");
      return takeAllAndRemoveFirst(taskDefinition, execution.getInstance());
    }
  }

  protected FlowNodeExecutionResult executeWithOptionalAsyncRetry(AbstractTaskDefinition taskDefinition, ExecutionContext execution) {
    try {
      if (Option.of(taskDefinition.getDelegateClass()).isPresent()) {
        HandlerCallDefinition callDefinition = new HandlerCallDefinition(execution.service(taskDefinition.getDelegateClass()));
        callDefinitionExecutor.execute(callDefinition, execution);
        return takeAllAndRemoveFirst(taskDefinition, execution.getInstance());
      } else if (Option.of(taskDefinition.getMethodCall()).isPresent()) {
        callDefinitionExecutor.execute(taskDefinition.getMethodCall(), execution);
        return takeAllAndRemoveFirst(taskDefinition, execution.getInstance());
      } else if(taskDefinition.getTaskScript().isPresent()) {
        scriptExecutor.execute(taskDefinition.getTaskScript().get(), execution);
        return takeAllAndRemoveFirst(taskDefinition, execution.getInstance());
      }
      throw new IllegalStateException("this method should only be called with executable " + taskDefinition);
    } catch (Exception executionException) {
      log.error(String.format("error during task (%s) execution: ", taskDefinition), executionException);
      if (taskDefinition.isRetryAsync()) {
        return scheduleRetry(executionException, taskDefinition, execution);
      }
      return takeNone(taskDefinition, execution.getInstance())
          .failed(true)
          .setException(executionException);
    }
  }

  private FlowNodeExecutionResult scheduleRetry(Exception e, AbstractTaskDefinition taskDefinition, ExecutionContext execution) {
    asyncTriggerScheduler
      .schedule(
        new AsyncTrigger()
          .incrementRetries()
          .withErrorDetails(new AsyncTriggerErrorDetails(e))
          .withNodeId(taskDefinition.getId())
          .withInstanceId(execution.getInstance().getIdentifier())
          .withDefinitionId(execution.getInstance().getDefinitionId())
      );
    return new FlowNodeExecutionResult(taskDefinition)
        .setException(e)
        .failed(true);
  }

  protected boolean isExecutable(AbstractTaskDefinition taskDefinition) {
    return taskDefinition.getDelegateClass() != null ||
            taskDefinition.getMethodCall() != null ||
            taskDefinition.getTaskScript().isPresent();
  }

  protected boolean goalIsFulfilled(GoalDefinition goal, ExecutionContext execution) {
    PredicateExpression goalPredicate = goal.getPredicate();

    return goalPredicate != null && expressionEvaluator.evaluate(goalPredicate, execution, Boolean.class);
  }

  protected void scheduleAsyncTask(AbstractTaskDefinition taskDefinition, ExecutionContext execution) {
    asyncTriggerScheduler
      .schedule(
        new AsyncTrigger()
          .withNodeId(taskDefinition.getId())
          .withInstanceId(execution.getInstance().getIdentifier())
          .withDefinitionId(execution.getInstance().getDefinitionId())
      );
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy