# class Step
As you customize your DATP application, you implement new steps by
defining a class that overrides the Step
object.
Your class represents a type of step, not an actual instance of a step
being run in a pipeline. At the time your invoke
and rollback
functions are
called, they will be provided an instance
parameter that represents the
specific step instance for which the function is being run.
The following is an example of a javascript module that implements a step.
class ExampleStep extends Step {
constructor(definition) {
super(definition)
this.someValue = definition.someValue
}
/**
* This function is called to run this step. The step instance parameter
* provides the context of the transaction and also convenience functions.
* @param {StepInstance} instance
*/
async invoke(instance) {
...
}
/**
* This function is called to undo whatever was previously done by the invoke function. * The step instance parameter provides the context of the transaction and also
* the convenience functions.
* If a rollback is not possible, or no rollback is required do not implement this
* function. If an error occurs during a rollback,
* @param {StepInstance} instance
*/
async rollback(instance) {
...
}
}
/**
* This function is called to register this as an available step type.
*/
async function register() {
await StepTypes.register(myDef, 'example/exampleStep', 'Example step')
}//- register
/**
*
* @param {Object} definition Object created from the JSON definition of the step in the pipeline.
* @returns New step instance
*/
async function factory(definition) {
const rec = new ExampleStep(definition)
return rec
}//- factory
const myDef = {
register,
factory,
}
export default myDef
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
Note that there are two functions external to the class that are returned by the Javascript module.
- The
register
function, which will be called by your application statup code to register this step type. It can then be used in pipelines. - The
factory
function, used by DATP to instantiate your step's class when it is required by a pipeline. Note that the pipeline passes a definition to this factory, so not all instances of this step type will be the same. You can write your step to perform however you like, based upon the definition it receives.
# constructor
Arguments:
{object} definition
Usage:
This is a standard class constructor. The
definition
parameter comes from the JSON definition for the step, in the pipeline definition. As mentioned above, it is entirely up to you what the definition should contain, and what your step will do with that definition.The constructor must first pass the definition to the constructor of the Step superclass, using
super(definition)
. Once that is done it should store away any values in the definition that will be used by theinvoke
androllback
functions.TIP
We recommend using private class variables (opens new window), which from ES16 are variables prefixed with a hash.
Example:
The definition in the pipeline:
{
message: 'Good morning',
amount: 123.45,
}
2
3
4
The constructor in your step class:
import Step from "../Step"
import StepTypes from '../StepTypeRegister'
class MyFavoriteStep extends Step {
#message
#amount
constructor(definition) {
super(definition)
this.#message = definition.message
this.#amount = definition.amount
}
...
}
2
3
4
5
6
7
8
9
10
11
12
13
14
- See also: Components
# invoke
Arguments:
{StepInstance} instance
Details of the step instance being run
Usage:
The invoke
function performs that actual functionality of the step. The
instance parameter provides the context of the transaction and also
convenience functions.
- Example:
async invoke(instance) {
// Write something to the transaction logbook
const stepId = instance.getStepId()
instance.log(instance.DEBUG, `MyFavoriteStep invoked [${stepId}]`)
// Get the data input to the step
const data = instance.getDataAsObject()
// Do something, using the data and details from the definition
const greeting = this.#message
data.newMessage = `${greeting} ${data.firstName}`
// Add credit to an account
instance.log(instance.DEBUG, `Crediting ${this.#amount} to account ${data.accountNo}`)
await creditAccount(data.accountNo, this.#amount)
// Time to complete the step and send a result
const note = ''
instance.log(instance.DEBUG, `MyFavoriteStep complete [${stepId}]`)
return await instance.succeeded(note, data)
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- See also: Application Config
# rollback
- Usage:
The rollback
function needs to undo any significant changes made when
invoke was called. It gets called if a step further down the pipeline from this
step fails, requiring that DATP back out every step that has already completed.
The instance parameter provides the context of the transaction and also convenience functions.
- Example:
async rollback(instance) {
// Write something to the transaction logbook
const stepId = instance.getStepid()
instance.log(instance.DEBUG, `MyFavoriteStep rolling back [${stepId}]`)
// Get the data input to the step
const data = instance.getDataAsObject()
// Remove the credit added to the account during 'invoke'
instance.log(instance.DEBUG, `Reversing credit of ${this.#amount} to account ${data.accountNo}`)
await creditAccount(data.accountNo, -data.amount)
// Finish up
instance.log(instance.DEBUG, `MyFavoriteStep roll back complete [${stepId}]`)
const note = '...'
return await instance.rolledBack(note, data)
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- See also: Application Config
# register
Returns:
{Promise<void>}
Usage:
You provide a
register
function that registers your step class with DATP.Then, in your application startup code you call the registration function to make your custom step type available to pipelines.
Note that this function is not a class function. It is a function exported by your Javascript module, that will be called by you in your server startup code.
Example:
MyFavoriteStep.js:
class MyFavoriteStep extends Step {
...
}
async function register() {
await StepTypes.register(myDef, 'me/myStep', 'My favorite step')
}//- register
const myDef = {
register,
factory,
}
export default myDef
2
3
4
5
6
7
8
9
10
11
12
13
app.js:
import MyFavoriteStep from `steps/MyFavoriteStep`
...
await MyStep.register()
2
3
4
5
# factory
Arguments:
{Object} definition
An object representation of the JSON data defining this step in the pipeline definition.
Returns:
{Promise<void>}
Usage:
Your factory function instantiates and returns your step class.
Note that this function is not a class function. It is a function exported by your Javascript module, that will be called by you in your server startup code.
Example:
MyStep.js:
async function factory(definition) {
return new MyFavoriteStep(definition)
}
2
3