Skip to content

Custom Code#

codeexecutionsvg

This task allows custom code to be executed in the system, similar to what happens with DEE Actions, creating an abstraction layer of code that can be used to aggregate several commands that can be more complex to create through the regular workflow editor.

customcode_01

Inputs#

Name Data Type Description
<custom list> <custom> Object with the inputs for the action
Activate any Executes the action in MES

Outputs#

Name Data Type Description
<custom list> <custom> Outputs of the action
Success Boolean If there was no problem emits a true
Error Error Error that occurred during the processing of this task

Settings#

On the General Tab, you have the usual settings and the following settings:

Name Data Type Default Description
Expiration Time Integer 10000 Time (in milliseconds) that the input values of an execution context are kept without a new value or an activation. 0 keeps them until the activation

customcode_02

On the Inputs Tab, there are the following settings:

Name Data Type Default Description
Name String An input name
Friendly Name String Name to be displayed
Type Long
Decimal
DateTime
Boolean
String
Integer
ReferenceType
...
The type of the input
Collection Type None
Array
Map
Default Value - Default Value

customcode_03

On the Outputs Tab, there are the following settings:

Name Data Type Default Description
Name String An output name
Friendly Name String Name to be displayed
Type Long
Decimal
DateTime
Boolean
String
Integer
ReferenceType
...
The type of the output
Collection Type None
Array
Map
Default Value - Default Value

customcode_04

On the Code Tab, there is a editor with syntax highlighting and intelligent code completion that allows the user to edit the code that should be run in this Task. This is the main focus point of the Task and should be used with care since it permits access to the MES itself through API calls, as well as storing values in a database table and perform logging of important values.

customcode_05

Here is an example of a direct MES interaction, where this Task calls a business method that removes all filled positions from a Container by the use of the EmptyContainer method:

import { Framework } from 'framework';

export default class {
    /** Allows accessing external functions */
    public framework: Framework;
    constructor(framework: Framework) {
        this.framework = framework;
    }
    /*
        * Entry point of the class (IMPORTANT: don't change the signature of this method)
        * Should return an object containing the values for each output to emit
        * If necessary, use the parameter "outputs" to emit data while running the code.
    */
    public async main(inputs: any, outputs: any): Promise<any> {
        // Add code here
        this.framework.logger.warning(inputs.xx);
        const input = new this.framework.LBOS.Cmf.Navigo.BusinessOrchestration.ContainerManagement.InputObjects.EmptyContainerInput();
        input.Container = new this.framework.LBOS.Cmf.Navigo.BusinessObjects.Container();
        input.Container.Name = "Container001";
        input.IgnoreLastServiceId = true;
        const output = await this.framework.system.call(input);
        this.framework.logger.error(JSON.stringify(output));
        // emit output during execution: outputs.output1.emit("something");
        // return example: return { output1: inputs.input1, output2: "Hello World" };
    }
}

Behavior#

This task executes the (TypeScript) code created by the user in the Code section of the Task settings. This code is executed with the received inputs and emits all the outputs defined in the code. Although similar to what happens in the execution of DEE Actions in MES, in this particular situation the user can have full control over the inputs and outputs of the block, with added configuration options for both scalar and reference types.

The main class must be the default export of the code:

export default class

The constructor of the class receives the framework object, which gives access to the namespaces listed below:

constructor(framework: Framework)

The framework object can then be used in a method that must have the following signature:

public async main(inputs: any, outputs: any): Promise<any>

Inside the main method the user can create code to access multiple namespaces. Here is a list of the available API namespaces and the methods and classes that can be used:

Datastore#

Object Type Description
clear method removes all values from the data store
delete method removes a value from the data store
listKeys method lists the identifiers in the data store
peekFromQueue method reads the next value of a queue without removing it
retrieve method retrieves value from the data store
retrieveFromQueue method retrieves and removes the next value of a queue
store method stores value to the data store
storeInQueue method stores a value at the end of a queue

Driver#

Object Type Description
automationControllerDriverDefinition property access to the driver definition of the current Automation Controller
connect method connects to the driver
disconnect method disconnects from the driver
executeCommand method executes a command
getProperties method gets property values from the driver
notifyRaw method sends notification to the driver
sendRaw method sends message to the driver
setProperties method sets property values in the driver

Logger#

Object Type Description
debug method logs debug message
error method logs error message
info method logs information message
warning method logs warning message

MessageBus#

Object Type Description
publish method sends message to the MessageBus
sendRequest method sends message to the MessageBus and waits for reply

System#

Object Type Description
call method calls an available API in the MES system

Utils#

Object Type Description
convertValueToType method runs a type conversion on a given input
ExecuteWithRetry method runs a function again, up to a number of attempts, while it fails
ExecuteWithSystemErrorRetry method runs a function again, up to a number of attempts, while it fails with specific MES system errors
sleep method places the system on pause for a predefined time

Remarks#

This Task should be used with care since a user may unwittingly introduce extra complexity in a workflow where a more simple way to perform specific tasks can be achieved by using simpler, more straightforward Tasks. Due to possible breaking changes (method signature changes, parameter renaming, among others), this Task should be used sparingly and when no other form of automation workflow is possible.

Every output named in the object returned by main is emitted, even when its value is null.

A new instance of the class is created for each execution, so a value kept in a class property is not available to the next execution.

The task keeps the input values of each execution context apart, and an activation runs the code with the values received in its own execution context. Values emitted on the same output in quick succession, with no await between them, reach a linked Data Flow task once, with the last value.

The task does not stop code that runs for a long time, and a loop that does not end blocks the Automation Controller.

The driver namespace is available only in a workflow associated with a driver. In any other workflow, framework.driver is not defined.

Info

As a quick tip for faster and easier development, pressing the combination of the Ctrl and S keys when editing the code inside the task will save the existing buffer.