Custom Code#
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.
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 |
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 | LongDecimalDateTimeBooleanStringIntegerReferenceType... | The type of the input | |
| Collection Type | NoneArrayMap | ||
| Default Value | - | Default Value |
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 | LongDecimalDateTimeBooleanStringIntegerReferenceType... | The type of the output | |
| Collection Type | NoneArrayMap | ||
| Default Value | - | Default Value |
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.
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:
The constructor of the class receives the framework object, which gives access to the namespaces listed below:
The framework object can then be used in a method that must have the following signature:
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.




