0.6.0 • Published 8 years ago

worky-mcworkflowface v0.6.0

Weekly downloads
2
License
MIT
Repository
-
Last release
8 years ago

worky-mcworkflowface

Build Status

A Javascript library for working with AWS's Simple Workflow Service.

Before using this, you should review:

Getting Started

  1. Register a SWF domain (if you need one).
  2. Write some workflows and activity tasks.
  3. Call init() with your configuration options.
  4. Register your activity tasks and workflows.
  5. Start decision and activity task pollers.

Or, in JS:

const AWS = require('aws-sdk');
const { init } = require('worky-mcworkflowface');
const {
    register,
    startActivityTaskPoller,
    startDecisionTaskPoller,
} = init({
    swfClient: new AWS.SWF(),
    domain: 'MyDomain',
    taskList: 'MainTaskList',
    workflowDefinitions: require('./workflows'),
    activityTaskDefinitions: require('./activities'),
});

register().then(() => {
    startActivityTaskPoller();
    startDecisionTaskPoller();
});

Logging

Log output is done via debug.

Namespaces are as follows:

  • swf:polling - Related to long-polling operations (for decision and activity tasks).
  • swf:registration - Related to registering workflows and activities with AWS.
  • swf:decider:<workflowId>:<runId> - For decision task execution.
  • swf:activity:<ActivityTaskName>:<workflowId>:<activityId> - For activity task + execution.

You should run with your DEBUG environment variable set to at least swf:* so you see error messages.

Public API

MethodDescription
init(Object)The main entry point. Returns a set of functions preconfigured for use in your environment.
distillEventsIntoItems(Array)Takes an array of SWF events from the AWS API and distills them into easier-to-digest items. Provided for use in testing your workflows with real data.

init(options)

This is the main API method. It accepts the following options:

OptionTypeDescription
swfClientAWS SWF client instance to use (e.g. new AWS.SWF()).
activityTaskDefinitionsArrayArray of Activity Task Definitions to use.
workflowDefinitionsArrayArray of Workflow Definitions to use.
domainStringSWF domain we are running in.
identityString(Optional.) Identity of this worker passed to SWF. Defaults to os.hostname().
taskListStringName of the task list we are using. Any decisions made requiring a task list will use this.

It returns an object with the following methods:

MethodDescription
register()Registers your workflows and activity tasks with SWF. Returns a Promise that resolves when registration completes.
resolveActivityTaskDefinition(name, version)Resolves a specific name + version combo of an activity task.
resolveWorkflowDefinition(name, version)Resolves a specific name + version combo of a decision task.
startActivityTaskPoller()Starts polling for and executing SWF Activity Tasks.
startDecisionTaskPoller()Starts polling for and executing SWF Decision Tasks.

Deciders

The core of each workflow is the Decider function. The decider is called repeatedly and receives a record of execution so far. Its job is to tell SWF the thing(s) to do next.

Here's an example:

function myDeciderFunction(workflowItems, availableDecisions) {
    const { startTimer, completeWorkflow } = availableDecisions;

    let timerItem = { started: false };

    // Scan through the workflow and look for a timer
    workflowItems.forEach((item) => {
        if (item.type === 'timer' && item.timerId === 'testTimer') {
            timerItem = item;
        }
    });

    if (!timerItem.started || timerItem.error) {
        // We have not started our timer or there was an error starting it.
        // Attempt to start it.
        return startTimer('testTimer', 30);
    }

    if (timerItem.fired) {
        // Timer has fired! All done.
        return completeWorkflow();
    }
}

Things to note about Decider functions:

  • They receive two arguments: items and availableDecisions
  • Can return one of the following:
    • An object describing a Decision
    • An array of either of the above

If your Decider throws an Error the associated decision task will be marked as failed and retried. Returning Promises from Deciders is not supported--your decider should execute synchronously, using Activity Tasks and Child Workflows for async processing.

availableDecisions

The following decision functions are passed into the decider as the second arg:

cancelTimer(timerId)
cancelWorkflowExecution()
completeWorkflowExecution(result)
continueAsNewWorkflowExecution(input)
failWorkflowExecution(err)
requestCancelExternalWorkflowExecution(workflowId)
startActivity(name, input)
startChildWorkflowExecution(type, id, input)
startTimer(timerId, seconds)

These functions are convenient factories for the objects described in AWS's respondDecisionTaskCompleted() docs.

WorkflowItems

SWF sends down a complete record of all events with each Decision task. This record can be difficult to parse, so we pre-process it. We merge associated events into single WorkflowItem for ease of reference.

Supported Item Types

typeDescription
activityAn attempt to execute an activity task.
child_workflowAnother workflow execution started via a startChildWorkflowExecution() decision.
signalAn external signal received by the workflow.
timerAn attempt to start a timer.
workflowThe current workflow execution. This will always be the first item.

TODO: Support other kinds of events.

Properties of activity, workflow, and child_workflow Items

PropertyTypeDescription
typeString"activity" or "workflow".
nameStringName of the activity or workflow.
versionStringVersion of the activity or workflow.
activityId or workflowIdStringID assigned to this activity or workflow execution.
canceledBoolWhether this item's execution was canceled.
cancelRequestedBoolWhether we've requested cancellation of this item's execution.
errorObjectIf execution failed, this will be an object with code and message fields describing why. Otherwise it will be undefined.
finishedAtDateDate/time execution stopped, whether due to successful completion, failure, or cancellation.
inProgressBoolWhether execution of this item is currently happening (that is, it has not completed or been canceled).
inputMixedInput to the activity or workflow.
resultMixedIf execution completed successfully, this will be the activity/workflow result.
startedBoolWhether execution has started.
startedAtDateWhen execution started.
successBoolWhether execution completed successfully.

Properties of timer Items

PropertyTypeDescription
typeString"timer".
timerIdStringTimer id. Pass to cancelTimer() decision.
canceledBoolWhether this timer has been canceled.
cancelRequestedBoolWhether we have requested to cancel this timer.
errorObjectIf there was an error starting this timer, it will be here.
firedBoolWhether this timer has fired (without being canceled).
firedAtDateTimestamp when this timer fired. If the timer has not fired, this will be undefined.
inProgressBoolWhether this timer is currently running.
startedBoolWhether this timer has started ticking.
startedAtDateWhen this timer started ticking. undefined if not started.

Properties of signal Items

PropertyTypeDescription
typeString"signal"
signalNameString
inputString

Representing Errors

Errors are represented in Workflow Items as objects with two fields: code and message. These fields map to the reason and details field used by the SWF API.


Workflow Definition

A Workflow Definition looks like this:

{
    name: "MyWorkflow",
    versions: {
        "1.0": {
            decider: function myOldDecider() { },
            settings: {
                /* various settings for workflow creation */
                defaultChildPolicy: 'TERMINATE',
                defaultTaskStartToCloseTimeout: '600',
            }
        },
        "1.1": {
            decider: function myNewDecider() { },
            settings: {
                /* etc. */
            }
        }
    }
}

Things to note:

  • Each version of a workflow must provide its own decider function and settings object.
  • settings are passed into the AWS SDK's registerWorkflowType() method.
  • Calling the register() function returned by init() will attempt to register each workflow version.

You provide your workflow definitions as an array via the workflowDefinitions option pass into init().

Activity Task Definition

An Activity Task Definition looks like this:

{
    name: "MyActivity",
    versions: {
        "1.0": {
            func: function myActivityFunction(input)
            settings: {
                /* settings for activity registration */
            },
        },
    }
}

Activity Task Definitions look like Workflow Definitions

Writing Activity Functions

An Activity function:

  • Receives a single argument, input
    • input can be any JSON-encodable type.
  • Can return a value or the Promise of a value.
    • Return values will be automatically passed through JSON.stringify(). Avoid returning values that cannot be serialized to JSON.
  • Can throw Errors.

Returning a rejected Promise or throwing an Error will result in the Activity Task Execution failing. Your decider will be passed the error details and can decide how to proceed.

0.6.0

8 years ago

0.5.0

8 years ago

0.4.0

8 years ago

0.3.0

8 years ago

0.2.1

8 years ago

0.2.0

8 years ago

0.1.0

8 years ago

0.0.1

8 years ago