Skip to main content
Version: Next

More Details

Now that you have seen a working example of the basics, it's time to look closer at what we did and add more to it.

More about the bootstrap configuration

The bootstrap is the only configuration the runtime needs in order to start. It contains the information required to load workflow configuration, either from a local file or a remote URL.

It also contains administrator-defined secrets and the host access rules, including the URLs and HTTP methods the runtime is allowed to use. These controls cannot be changed remotely by workflow logic.

The bootstrap can contain multiple deployment definitions. Each one runs in its own isolated context, with its own secrets and host definitions.

You can review the API reference for the bootstrap. It is detailed, but even a brief skim will show you the range of settings that can be configured.

In the previous example, we set the minimum requirements to get the bootstrap working. Here are the properties we added and what they do:

  • remoteConfiguration: the workflow configuration produced by the packager. This can be a file local to the runtime or a URL.
  • deploymentId: a unique identifier used to tag metrics and logs produced while loading the deployment.
  • agentPrivateKey: the private key used to decrypt the workflow configuration. It matches the public key used to package the configuration.

Other configurable properties include the configuration check interval, authentication headers, bootstrap load error handling, and the host definitions the runtime is allowed to communicate with.

More about the workflow configuration

The workflow configuration is how the runtime receives instructions for the tasks you want it to perform.

In the previous example, we defined workflows. This is the main body of a workflow configuration and defines the tasks and steps you want the runtime to perform.

In the example, we defined a single Workflow and gave it a unique name. We also defined a single Step. It was a very simple step that printed hello world.

A Step is the most fundamental unit in an Opscotch workflow. It is a templated action that generally does the following:

  • make a call to a URL
  • process the response
  • take zero or more actions

The actions that can be taken generally include:

  • send a metric
  • invoke one or more steps

The ability to invoke one or more steps means that you can build a graph of tasks. That makes it possible to construct sophisticated workflows that obtain the data you need, process it, and deliver it where it needs to go.

For example, the first step might retrieve a value from an API. It can then assess that value and, if required, invoke another step that sends a message to Slack. That Slack step might call a webhook URL, confirm that the request was accepted, and then send a metric recording that the Slack message was sent.

This is how we can chain steps together to create a sophisticated workflow.

More about the step

As mentioned previously, the Step is the fundamental building block of an Opscotch workflow. Each step performs a discrete task, and you arrange steps to create a more sophisticated workflow.

The step is a templated function. It has a predefined execution order, and you provide the specific implementation for each hook in that pattern. In the pattern described above, the available hooks are:

  • authenticationProcessor: optionally lets you prepare for authentication challenges, including calling another workflow to obtain credentials.
  • splitGenerator: optionally transforms input data into a list of items to iterate over.
  • urlGenerator: constructs the HTTP URL to call, optionally once per item generated by splitGenerator.
  • payloadGenerator: constructs the HTTP request body, such as JSON or form data.
  • itemResultProcessor: when using splitGenerator, optionally processes each individual response.
  • resultsProcessor: evaluates the final HTTP response and decides what action to take next.

Each of these hooks is expressed as a JavascriptSource, where you define the required logic in JavaScript.

The JavaScriptSource

In the previous example, we created a JavascriptSource that printed Hello World.

The JavascriptSource is a blank canvas where you define how to process data in JavaScript. It runs inside the runtime in an isolated context and has access to a very limited set of data and functions.

The JavascriptSource has two important properties:

  • script: defines JavaScript directly in the workflow configuration. This is what we used in the previous example.
  • resource: includes a resource file containing self-contained JavaScript. This is the more common approach.

These are available as properties on the JavascriptSource object and are useful when you only have a single script to execute:

{
"payloadGenerator" : {
"resource" : "..."
}
}

However, if you want to execute multiple scripts for the same step source, you can wrap them in the processors array:

{
"payloadGenerator" : {
"processors": [
{
"resource" : "..."
},
{
"resource" : "..."
}
]
}
}

The JavaScriptContext

The JavascriptContext is the only bridge between the JavascriptSource and the runtime. It provides a highly controlled execution environment. Inside the JavascriptSource, the JavascriptContext is available through the context object, for example context.getData().

The JavascriptContext exposes several data access points. The values are provided in raw form, so you may need to parse them, for example JSON.parse(context.getPassedMessageAsString()):

  • context.getPassedMessageAsString(): returns the message body that was passed to the step.
  • context.getMessageBodyAsString(): returns the current message body. This may change during step execution, for example after an HTTP call completes.
  • context.getData(): returns the data structure provided to the step in the configuration.

It also provides functions for:

  • send message to another step or send a metric
  • work with timestamps
  • work with step properties
  • work with persistent data
  • work with HTTP headers, URLs and payload bodies

Be sure to review the JavascriptContext API for all the functions.

The data property

The data property appears on many objects, and those objects form a tree hierarchy with the JavaScriptSource at the leaf. When the runtime loads each JavaScriptSource, it traverses up the parent nodes and merges configuration data. As a result, each JavaScriptSource has access to the data properties of its ancestors, including the bootstrap.

The trigger property

The trigger property is defined on steps that should start a workflow execution, so it is optional. In the example, the trigger was configured to run once when the runtime starts by setting "runOnce" : true.

Take a look at the other options on Trigger.

Resource files

Resource files let you store reusable or more complex JavaScript outside the main workflow JSON. In the previous example, the packager configuration included "resourceDirs" : ["."], which defined a resource directory but did not use it. In a more typical setup, resourceDirs is an array of directories that the packager or test runner can access, such as "resourceDirs" : ["./resources"]. The exact path depends on where you store your resources.

Wrapping up

You now have more detail about how to move from the Hello World example to more sophisticated workflows.

Next, look at a full example that builds on what you have learned.