Documentation

Workflow engine

Digital HUB

Each workflow execution is assigned an execution context and a (UUID). The UUID identifies a Customer throughout the whole workflow execution.

The execution context stores the current state of a workflow execution as a set of context attributes.

Context attributes

The context attributes define a data model for the corresponding workflow definition. The attributes are hierarchical, and are used for sharing data between different workflow commands and making flow control decisions.

Each attribute can be accessed by its key, such as client.address.city

There are two ways that the context attributes can be set and updated:

  • specifying a route or exchange namespace
  • specifying an attribute directly using an object, route or exchange result

config.logo << 'http://logo.png'
products << [product1: "Product1", product2: "Product2"]
route('products') { namespace product }
client.basic << route('basic info')
credit << exchange('credit check')

Execution UUID

Execution UUID is a predefined context attribute which can be used to distinguish a user session or as a specific info in a connector request to provide a relation to each execution for an external or internal service.

uuid - context unique identifier

Usage:


exchange('sendinfo') {
   tosend.sessionId << uuid
}

Workflow Execution

Workflow is managed using the following:

  • route checkpoint
  • route validation
  • exchange validation
  • function update
  • failed exchange
  • execution termination

Executor life-cycle

A separate executor handles each workflow execution, including:

  • Executor persistence
  • Discards the DSL executor context after execution terminates
  • Executor expiration is set using hub.executor.expiration. The default is 8 hours.

DSL

Each DO process is defined by a workflow using a custom DSL (Domain Specific Language).

The workflow DSL provides the following commands:

  • route
  • exchange
  • path
  • function
  • match
  • exist
  • switch / case
  • loop-until
  • lookup

See the subsections below for an explanation of each.

route

A route corresponds to a page or screen, depending on the Hub Client implementation. The purpose is to display route-specific information and gather customer input.

A route payload, submitted via Hub Client, is validated using the validate payload specification and stored as Context attributes using the namespace.


route('name') {
    uri '/uri'
    export data
    function 'fnc1', 'fnc2, ...
    validate { payload specification }
    namespace namespace
    checkpoint()
    terminal(result)
}


Parameters:

  • name identifies a route for registration and logging purposes
  • uri identifies a route for Hub Client
  • export data passed to a Hub Client, can be any serializable object, e.g. string, map, list, context attribute via its key
  • function a list of route functions, i.e. functions available within the route
  • validate route payload specification
  • namespace used for storing route payload
  • checkpoint() marks a route as a checkpoint, i.e. disables going back from this route
  • terminal() marks a route as terminal and checkpoint, a result can be specified or omitted

See route examples for more details.

exchange

Makes an external (API) call using a connector (specified by a type) with a connector-specific configuration. To handle a connector failures, a timeout, retries and fallback can be specified. A randomized exponential backoff strategy is used for connector retries. An exchange is executed asynchronously when marked with async(). The connector result is validated using a payload specification and stored as a context attribute under the namespace.


exchange('name') {
    connector 'type'
    config configuration
    fallback {
        workflow
    }
    async()
    timeout 30
    retry 3
    retryBackoff 5
    validate { payload specification }
    namespace namespace
}

Parameters:

  • name for registration and logging purposes
  • connector a connector specified by a type, see Connectors
  • config a connector custom configuration
  • fallback a workflow to be executed when exchange fails
  • async() marks an exchange to be executed asynchronously
  • timeout a number of seconds before an exchange timeouts and fails, the default timeout is 30s
  • retry a number of retries in case of a connector failure, the default number of retries is 3
  • retryBackoff a number of seconds before first retry, the default retryBackoff is 5s
  • validate specifies an exchange result validation
  • namespace for exporting exchange result as context attribute

path

Executes a registered path (sub-workflow) specified by a name.


path 'name'

function

A function makes it possible to query dynamic data, perform complex calculations or make external calls using exhange(). Functions be used within a workflow as well as by a Hub client via Hub Client API. A function scope, either 'global' or 'route', controls the corresponding function availability via the REST API. Global functions are available throughout the whole workflow execution, whereas a 'route' function is only available within a specific route.


function('name') {
    script
}

match

Executes a workflow when an expression is true. The expression can contain context attributes.


match (expression) {
    workflow
}

exist

Executes a workflow when an attribute is set.


exist (attribute) {
    workflow
}

switch / case

The switch statement matches expression with cases and executes the matching case.

It's a fallthrough switch-case. You can share the same code for multiple matches or use the break command.

It uses different kinds of matching like, collection case, regular expression case, closure case and equals case.


switch (expression) {
    case "bar":
        route "Bar"

    case ~/fo*/:
        route "Foo"
        break

    case [4, 5, 6, 'inList']:
        route "Matched
        break

    default:
        route "Default"
}

loop-until

Executes a workflow until an expression is true. Optionally, you can specify a maximum number of the workflow block is executed.


loop {
    workflow
} until (expression)

loop(number) {
    workflow
} until (expression)

lookup

Looks up existing (active or expired) execution context matching a condition. The condition is specified as a context attribute. An execution context is matched if it contains the condition attribute. Active executions are tried first. If no active execution context matches the condition, the expired executions are tried. This applied only when execution are persisted, i.e. the logger profile is active.


lookup(client.mobile)
existing << lookup(pco.applicationId)

Command registration

In a command registration, you register and use a command configuration by employing a name. The purpose is to enable reuse of a command configuration in a workflow script.

The following command configurations can be registered: - route(name) - exhange(name) - path(name) - function(name) - global function(name)

Here's a general example of registration for a route command:


register {
    route('basic') {
        uri '/basic'
    }
}

route 'basic'
route('basic') {
    terminal()
}

In addition, a registered command configuration is useful as a template that may be refined further in a workflow script.

The following example illustrates a command registration, usage (as-is), and configuration refinement.

As seen in this example, a global exchange configuration can be registered to configure a default exchange fallback, timeout, and retry policy.


register {
    exchange {
        retry 5
        timeout 15
        fallback {
            route 'error'
        }
    }
}

Payload validation

The validate block is used for route and exchange results validation.

It specifies a result (fields) structure and data constrains.

A field is defined by a name, data constrains (validators) and nested fields. The default validator for a field is mandatory, i.e. a field is mandatory if listed.

You can use the following validators - string() a field must be a string - number() a field must be a number - truefalse() a field must be a boolean - file() a field must be a file descriptor - file mimeType a field must be a file descriptor and match the mime type, e.g. application/pdf, image, etc. - oneOf value1, value2, ... a list of values, a field data must be one of the values - regex ~/pattern/ a regular expression to match a field data, the expression can be a string or a groovy regex pattern syntax

Here is an example:


validate {
    firstname
    lastname
    address {
            city { values "Prague", "Paris" }
            zip { regex ~/^[0-9]{5}(?:-[0-9]{4})?$/ }
        }
}

See validate examples for more details.

Workflow validation

  • check for invalid DSL commands
  • validate DSL command specification (uri is mandatory for route)
  • validate connector configurations (http connector must have url...)
  • validate context attribute usage, i.e. if an attribute was set before being used