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

example.ExampleWorkflowService Maven / Gradle / Ivy

There is a newer version: 5.2
Show newest version
package example;

import com.amazonaws.AbortedException;
import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflow;
import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflowClient;
import com.amazonaws.services.simpleworkflow.model.ActivityTask;
import com.amazonaws.services.simpleworkflow.model.DecisionTask;
import com.amazonaws.services.simpleworkflow.model.RespondActivityTaskCompletedRequest;
import com.amazonaws.services.simpleworkflow.model.RespondDecisionTaskCompletedRequest;
import com.amazonaws.services.simpleworkflow.model.WorkflowExecution;
import com.amazonaws.services.simpleworkflow.model.WorkflowExecutionInfo;
import com.bazaarvoice.sswf.Builders;
import com.bazaarvoice.sswf.Logger;
import com.bazaarvoice.sswf.model.DefinedStep;
import com.bazaarvoice.sswf.model.history.StepEvent;
import com.bazaarvoice.sswf.model.history.StepsHistory;
import com.bazaarvoice.sswf.service.StepActionWorker;
import com.bazaarvoice.sswf.service.StepDecisionWorker;
import com.bazaarvoice.sswf.service.WorkflowManagement;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ExampleWorkflowService {
    final AmazonSimpleWorkflow swf = new AmazonSimpleWorkflowClient(); // grabs the credentials from your env
    final String domain = "java-sswf-example";
    final String workflow = "example-java-workflow";
    final String workflowVersion = "0.4";
    final String taskList = "my-machine";
    final Logger logger = new StdOutLogger();

    final ExampleWorkflowInput.Parser inputParser = new ExampleWorkflowInput.Parser();
    final WorkflowManagement workflowManagement =
        new Builders.WorkflowManagementBuilder<>(ExampleWorkflowInput.class, ExampleWorkflowSteps.class)
            .setDomain(domain)
            .setWorkflow(workflow)
            .setWorkflowVersion(workflowVersion)
            .setTaskList(taskList)
            .setSwf(swf)
            .setWorkflowExecutionTimeoutSeconds(60 * 60 * 24 * 30)
            .setWorkflowExecutionRetentionPeriodDays(30)
            .setStepScheduleToStartTimeoutSeconds(30)
            .setInputParser(inputParser)
            .setLogger(logger)
            .build();

    final ExampleSignalHandler signalHandler = new ExampleSignalHandler(workflowManagement);
    final ExampleWorkflowDefinition workflowDefinition = new ExampleWorkflowDefinition(workflowManagement, signalHandler);

    final StepDecisionWorker decisionWorker =
        new Builders.StepDecisionWorkerBuilder<>(ExampleWorkflowInput.class, ExampleWorkflowSteps.class)
            .setDomain(domain)
            .setTaskList(taskList)
            .setSwf(swf)
            .setInputParser(inputParser)
            .setWorkflowDefinition(workflowDefinition)
            .setLogger(logger)
            .build();
    final StepActionWorker actionWorker =
        new Builders.StepActionWorkerBuilder<>(ExampleWorkflowInput.class, ExampleWorkflowSteps.class)
            .setDomain(domain)
            .setTaskList(taskList)
            .setSwf(swf)
            .setInputParser(inputParser)
            .setWorkflowDefinition(workflowDefinition)
            .setLogger(logger)
            .build();

    final ScheduledExecutorService decisionExecutor = Executors.newSingleThreadScheduledExecutor();
    final ScheduledExecutorService actionExecutor = Executors.newScheduledThreadPool(3); // We'll let a few actions (from different workflow executions run cuncurrently)

    final ExecutorService actionWorkers = Executors.newCachedThreadPool();

    public void start() {
        workflowManagement.registerWorkflow();

        signalHandler.start();

        decisionExecutor.scheduleAtFixedRate(() -> {
            try {
                System.out.println("Decision: polling for work");
                DecisionTask task = decisionWorker.pollForDecisionsToMake();

                while (task != null) {
                    System.out.println("Decision: got task for " + task.getWorkflowExecution());
                    final RespondDecisionTaskCompletedRequest completedRequest = decisionWorker.makeDecision(task);
                    System.out.println("Decision: made decision " + (completedRequest == null ? "null" : completedRequest.getDecisions()));

                    task = decisionWorker.pollForDecisionsToMake();
                }

                System.out.println("Decision: Got no task...");

                System.out.println("Decision: done");
            } catch (AbortedException e) {
                System.out.println("Decision thread shutting down.");
            } catch (Throwable t) { // Make sure this thread can't die silently!
                System.err.println("Decision: unexpected exception. Continuing...");
                t.printStackTrace(System.err);
            }
        }, 5, 5, TimeUnit.SECONDS);

        actionExecutor.scheduleAtFixedRate(() -> {
            try {
                System.out.println("Action: polling for work");
                ActivityTask task = actionWorker.pollForWork();
                while (task != null) {
                    final ActivityTask finalTask = task;
                    actionWorkers.submit(() -> {
                        try {
                            System.out.println("Action: got task for " + finalTask.getWorkflowExecution());
                            final RespondActivityTaskCompletedRequest completedRequest = actionWorker.doWork(finalTask);
                            System.out.println("Action: complete for " + finalTask.getWorkflowExecution() + ": " + (completedRequest == null ? "null" : completedRequest.getResult()));
                        } catch (Throwable t) {
                            // This thread isn't important to safeguard, since the executor will make another one next submit().
                            // I'm printing the error for your benefit in the example.
                            System.err.println("Action: unexpected exception executing work.");
                            t.printStackTrace(System.err);
                            throw t;
                        }
                    });
                    task = actionWorker.pollForWork();
                }

                System.out.println("Action: Got no task...");

                System.out.println("Action: done");
            } catch (AbortedException e) {
                System.out.println("Action poller thread shutting down.");
            } catch (Throwable t) { // Make sure this thread can't die silently!
                System.err.println("Action: unexpected exception polling/submitting. Continuing...");
                t.printStackTrace(System.err);
            }
        }, 15, 5, TimeUnit.SECONDS);
    }

    public void stop() {
        decisionExecutor.shutdownNow();
        actionExecutor.shutdownNow();
    }

    public static void main(String[] args) throws InterruptedException {
        final Date runStart = new Date();
        // start all the workers
        final ExampleWorkflowService service = new ExampleWorkflowService();
        service.start();

        // submit a workflow for fun
        startWorkflowForFunAndProfit(service);
        // submit another one for profit
        startWorkflowForFunAndProfit(service);
        // submit a third for profit
        startWorkflowForFunAndProfit(service);

        boolean oneExtractCancelled = false;
        boolean oneNonExtractCancelled = false;

        while (true) {
            Thread.sleep(5000);
            final List executions = service.workflowManagement.listOpenExecutions(new Date(System.currentTimeMillis() - 1000 * 60 * 60 * 24), new Date());
            for (WorkflowExecutionInfo executionInfo : executions) {
                final StepsHistory execution = service.workflowManagement.describeExecution(executionInfo.getExecution().getWorkflowId(), executionInfo.getExecution().getRunId());
                System.out.println("");
                System.out.println("WF history: " + executionInfo.getExecution());
                System.out.println("  input: " + execution.input());
                System.out.println("  firedTimers: " + execution.firedTimers());
                System.out.println("  events:");
                StepEvent lastEvent = null;
                for (StepEvent event : execution.events()) {
                    System.out.println("    " + event);
                    lastEvent = event;
                }
                System.out.println();

                // This simulates an external user deciding to cancel the workflow while a long-running step is in progress.
                if (lastEvent != null && !oneExtractCancelled &&
                    lastEvent.event().isLeft() && lastEvent.event().left().get() instanceof DefinedStep &&
                    ((DefinedStep) lastEvent.event().left().get()).step() == ExampleWorkflowSteps.EXTRACT_STEP && Objects.equals(lastEvent.result(), "STARTED")) {
                    System.out.println("Cancelling workflow!");
                    service.workflowManagement.cancelWorkflowExecution(executionInfo.getExecution().getWorkflowId(), executionInfo.getExecution().getRunId());
                    oneExtractCancelled = true;
                }

                // This simulates an external user deciding to cancel the workflow in between steps or during a step that does not respect cancellation requests
                if (lastEvent != null && !oneNonExtractCancelled &&
                    lastEvent.event().isLeft() && lastEvent.event().left().get() instanceof DefinedStep &&
                    ((DefinedStep) lastEvent.event().left().get()).step() != ExampleWorkflowSteps.EXTRACT_STEP) {
                    System.out.println("Cancelling workflow!");
                    service.workflowManagement.cancelWorkflowExecution(executionInfo.getExecution().getWorkflowId(), executionInfo.getExecution().getRunId());
                    oneNonExtractCancelled = true;
                }
            }
            if (executions.size() == 0) {
                System.out.println("all workflows are done!");
                break;
            } else {
                System.out.println(executions.size() + " workflows are still open.");
            }
        }

        final List executions = service.workflowManagement.listClosedExecutions(runStart, new Date());
        System.out.println("\nExecutions this run:");
        for (WorkflowExecutionInfo executionInfo : executions) {
            final StepsHistory execution = service.workflowManagement.describeExecution(executionInfo.getExecution().getWorkflowId(), executionInfo.getExecution().getRunId());
            System.out.println("");
            System.out.println("WF history: " + executionInfo.getExecution());
            System.out.println("  input: " + execution.input());
            System.out.println("  firedTimers: " + execution.firedTimers());
            System.out.println("  events:");
            for (StepEvent event : execution.events()) {
                System.out.println("    " + event);
            }
            System.out.println();
        }

        // stop everything and exit
        System.out.println("shutting down...");
        service.stop();
    }

    private static void startWorkflowForFunAndProfit(final ExampleWorkflowService service) {
        final int rando = new Random().nextInt(Integer.MAX_VALUE);
        final ExampleWorkflowInput input = new ExampleWorkflowInput("example-input-parameter-value-" + rando);
        final WorkflowExecution workflowExecution = service.workflowManagement.startWorkflow("workflow-" + rando, input);
        System.out.println("started " + workflowExecution);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy