Scripting

Capabilities

Capability

Support

Comment

Back-pressure

Supported feature

Controls what happens when executions arrive faster than the script can process them. Supports DROP_OLDEST and DROP_LATEST strategies, configurable per script. See Backpressure and buffering.

Priority scheduling

Supported feature

Scripts competing for the same execution pipeline are dispatched in priority order (lower value = higher priority). Scripts sharing the same priority are dispatched in strict arrival order (FIFO). See Priority scheduling.

Execution validity (TTL)

Supported feature

A maximum age can be set on pending executions. Executions that have been waiting longer than the configured duration are silently discarded, preventing stale runs after a backlog or burst. See Priority scheduling.

Concurrent execution limit

Supported feature

The maximum number of simultaneous executions of the same detached script can be bounded, preventing overload on external services that do not support parallel sessions. See Priority scheduling.

Per-trigger independent queuing

Supported feature

Detached scripts triggered by multiple independent value sources can assign a separate queue and concurrency slot to each distinct trigger, avoiding head-of-line blocking between unrelated sources. See Priority scheduling.

Read/update values

Supported feature

Scripts can read any value from the hierarchy and write back computed results. Owner (value) scripts expose the bound value through the myself object. See Read and update Values.

Logging

Supported feature

Scripts can emit structured log entries at configurable severity levels, visible in the OnSphere log console. See Logging.

Milestone trigger event

Supported feature

Scripts can publish milestone events to mark significant points in time on the hierarchy, usable for auditing and dashboards. See Milestone.

Importing script

Supported feature

Scripts can import reusable modules written as .mjs files using the standard ES import keyword, allowing shared libraries across multiple scripts. See Import scripts.

Scheduling executions

Supported feature

Scripts can be executed on a recurring schedule using Quartz cron expressions, independently of any value trigger. See Scheduled executions.

Interact with alarms

Supported feature

Scripts can create, acknowledge, and query alarms on the hierarchy programmatically. See Alarms manipulation.

Interact with collections

Supported feature

Scripts can read and write to OnSphere collections, enabling persistent storage of structured data across script executions. See Collections.

Validate data with filters

Supported feature

Scripts can apply filter expressions to validate or transform data before processing. See Alarm or collection filter.

Sending notification (SMS/EMAIL)

Supported feature

Scripts can send SMS and email notifications through the OnSphere communications service. See Communications.

Get the list of users

Supported feature

Scripts can query the list of OnSphere users, for example to resolve notification recipients dynamically. See Keycloak users.

Format JS dates

Supported feature

Scripts have access to a timestamp controller providing formatting and conversion utilities for JavaScript date values. See Date converter and formatter.

Generate random UUID

Supported feature

Scripts can generate unique identifiers on demand, useful for creating records in external systems or collections. See Generate UUIDv4 ids.

Sending SNMP TRAP

Supported feature

Scripts can emit SNMP TRAPs to external management systems. See Sending SNMP TRAP.

Replaying SNMP TRAP

Supported feature

Scripts can replay a previously received SNMP TRAP, for example to forward it to another NMS. See snmp.replayTrap().

HTTP request

Supported feature

Scripts can perform outbound HTTP and HTTPS requests to interact with external REST APIs or web services. See HTTP requests.

Ping request

Supported feature

Scripts can issue ICMP ping requests to check the reachability of network hosts. See Network.

Analytics request

Supported feature

Scripts can query the OnSphere analytics engine to retrieve aggregated or historical data for use in computations. See Analytics.

Javascript auto-completion (composer)

Supported feature

The OnSphere Composer provides IntelliSense-style auto-completion for the scripting API, reducing errors and speeding up development. See script auto-complexion.

Concepts

Overview

The osp-scripts plugin provides the ability to execute scripts written in Javascript and to interact with hierarchy elements and external systems.

Behavior

The osp-scripts provides a Javascript engine based on GraalVM, on which scripts are run on transient contexts, meaning that they do not have persistent state on their own (setting a value to a variable defined in the global scope of the script will be forgotten in the next script execution).

Scripts come in two forms :

  • Value scripts : Those scripts are bound to a value in the hierarchy and their result is used to generate the value content. They provide a way of computing a complex state and provide it to the hierarchy.

  • Detached scripts : Those scripts are detached from the hierarchy. They provide a way to execute actions on the hierarchy or on external systems.

Scripts executions follow the following constraints :

  • A script is guaranteed to have the view of the hierarchy as it was when it was triggered, independently of potential execution delays

  • If a value triggers the execution of multiple scripts, all scripts are guaranteed to have the same hierarchy view

  • Executions of different scripts are always run in parallel

  • Executions of the same value script are always run sequentially, for coherent update of their value

  • Executions of the same detached script are always run in parallel

../../_images/execution-order-example.png

Script execution

The script execution use a shared pool of threads, this pool must fit the need of the current installation with a tradeoff between :

  • Memory usage

  • Context switching

  • I/O duration

Warning

In general, the number of threads should be increased in case of a high number of scripts running at the same time. The more scripts are idle (like waiting on an external system), the more threads can be increased to increase throughput. But there is a drawback, each thread consumes memory and in case of too many context switches, the overall performance of the system can be affected.

Concurrency

The values.scripts and detached.scripts are not executed in the same manner.

Values scripts These are executed sequentially by values. This means that if the value root.value-A changes multiple times, the scripts will run one after another in order. However, if two values are modified simultaneously, both scripts may run concurrently.

Warning

If multiple script modules are used, the execution process can run in parallel, as the sequential triggering protection is managed locally within each module.

Detached.scripts These are executed only when triggered. If multiple scripts are triggered simultaneously, they run in parallel.

Handle concurrency The integrator is responsible for managing concurrency issues. When multiple scripts or processes are executed simultaneously, it is up to the integrator to ensure proper synchronization, avoid race conditions, and maintain data consistency. By implementing appropriate concurrency controls, the integrator guarantees that parallel executions do not lead to conflicts or unexpected behaviors.

Below are two examples. The first example illustrates logging into a service that does not support multiple simultaneous login processes. It shows a scenario where the same value is triggered twice. The executions are performed sequentially, ensuring everything works as expected.

callbackForValue1 -> WebSite : Login
WebSite -> callbackForValue1 : 200, ok
callbackForValue1 -> WebSite : doSomeAction
WebSite -> callbackForValue1 : 200, ok

callbackForValue1 -> WebSite : Login
WebSite -> callbackForValue1 : 200, ok
callbackForValue1 -> WebSite : doSomeAction
WebSite -> callbackForValue1 : 200, ok

In the second example, the scripts are triggered by two different values, allowing the logins to occur simultaneously, which can result in an error, when the first scripts will be logged off.

callbackForValue1 -> WebSite : Login
WebSite -> callbackForValue1 : 200, ok
callbackForValue2 -> WebSite : Login
WebSite -> callbackForValue2 : 200, ok
WebSite -> callbackForValue1 : Connection closed (new connection)
callbackForValue1 -> WebSite : doAction
WebSite -> callbackForValue1 : 401, unauthenticated
callbackForValue2 -> WebSite : doSomeAction

Backpressure and buffering

Each script execution is dispatched to a shared thread pool. When executions arrive faster than they can be processed, pending executions are queued per script.

The maxInFlightExecutions parameter controls how many executions (queued and running combined) are kept in memory for a given script:

  • -1 — unlimited. Every incoming execution is accepted. Use with care on high-frequency triggers to avoid unbounded memory growth.

  • 0 — disabled. All executions are unconditionally rejected (kill-switch to pause a script without removing its configuration).

  • > 0 — bounded. When pending + running reaches the limit, the backpressureStrategy determines what happens to the excess execution.

When the limit is reached, one of two strategies applies:

  • DROP_OLDEST (default) — discards the oldest pending execution to make room for the new one. If the queue is empty (all slots are occupied by running executions), the incoming execution is dropped instead.

  • DROP_LATEST — discards the incoming execution, keeping the existing queue intact.

Configure both parameters in owner.scripts and detached.scripts.

Priority scheduling

Scripts sharing the same execution pipeline compete for thread-pool slots according to a priority-based scheduler.

priority

Scheduling priority relative to other scripts in the same pipeline. Lower values run first. Scripts with equal priority are dispatched in strict arrival order (FIFO). Default: 50. Minimum: 0.

validity

Maximum age of a pending execution. If an execution has been waiting in the queue longer than this duration, it is silently discarded when the scheduler attempts to run it. Useful to prevent stale executions from running after a burst or a pause. If not set, pending executions never expire.

maxConcurrentExecutions (detached scripts only)

Maximum number of executions of the same detached script running simultaneously. Default: 1. Use values above 1 with care when the script interacts with external services that do not support concurrent sessions.

useTriggerAsId (detached scripts only)

When true, the scheduling key is composed of the script name and the trigger id instead of the script name alone. This gives each distinct trigger value its own independent queue and concurrency slot within the shared pipeline. Default: false. Use this when the same script is triggered by several independent value sources that should be queued separately.

Note

maxConcurrentExecutions and useTriggerAsId do not apply to owner (value) scripts, which are always executed sequentially per value by design.

Trigger information

Scripts can access the reason that triggered their execution by global variable trigger (trigger.id, trigger.content, …).

A trigger has the following structure :

  • id : the id of the value (string)

  • name : the name of the value (string)

  • description : the description of the value (string)

  • content (nullable) : the content of the value, can be null in case of reading errors (boolean, number or string depending on the type field)

  • error : the error in case of error, empty otherwise (string)

  • type : BOOLEAN, INTEGER, DECIMAL, TEXT (string)

  • timestamp : the timestamp attached to the value (integer)

Note

For detached scripts executed manually (i.e., not from callbacks, like an explicit call to scripts.run()), trigger only provides following fields :

  • id : always contains internal.manual, useful to determine if script was triggered manually or by a callback (string)

  • parameters : parameters list that were provided to the script (string[])

Warning

Owner script can only be triggered by callbacks. Manual actions like Actions can’t trigger an owner script.

myself object

Value scripts can access the myself object (detached scripts cannot). It contains the value linked to the script. Using the myself object is equivalent to using values.get(<value_id>) and has the same methods available:

Import scripts

Inside your scripts you may need some additional modules or functions. This section explain how to import them in your configuration. Here are some restrictions:

  • You need the source code you want to include (no package importation).

  • Only scripts with .mjs file extension can make use of the import keyword (it will be ignored if the extension is simply .js).

  • Objects or functions you want to import have to be marked with the export keyword.

Warning

All import are relative to root/.

Note

If you have a script with .js extension, you can freely rename it to .mjs.

A script can be imported with the following step

  1. Add you library in your configuration directory.

...
├── certs
├── keys
├── modules
├── root
│   └── lib
│       └── my_lib.mjs
├── schema
├── stack
...
  1. Add an import statement in your script:

import { my_function } from "lib/my_lib.mjs";

Note

The path to your script can be relative or absolute. We recommend to use absolute path as they will be static when the script is moved.

  1. Add an entry in the file : modules/scripts/<module_script>/module.resources:

"resources": [
  {
    "source": "root/lib/",
    "destination": "root/lib/"
  }
]
  1. Configure tsconfig.json to enable the auto-completion:

This configuration indicate the js lint where to find the source to enable the auto-completion.

{
  "extends": "./tsconfig.onsphere.json",
  "compilerOptions": {
    "paths": {
      "*": ["./root/*"]
    },
  }
}

Scheduled executions

Scripts executions can be scheduled periodically using cron expressions. The precision of those expressions is at the second, for example * * * * * ? * will schedule a script every second.

The expected format is <Seconds> <Minutes> <Hours> <Day of month> <Month> <Day of week> <Year>.

For example, the following expression schedule one execution every:

  • seconds: * * * ? * * *

  • 10 seconds: 0/10 * * ? * * *

  • monday at 13:00: 0 0 13 ? * MON *

  • every hour at 0 and 30 minutes: 0 0,30 * ? * * *

  • every first day of each month: 0 0 0 1/1 * ? *

The / can be used to specify a start time and an interval (every x seconds starting at y second).

The , can be used to define the multiple execution points (At 10, 25, 45 seconds).

The ? is only used for the field Day of month and Day of week because they are mutually exclusive. For example, setting an execution on the first day of every month and every Monday on the same expression is not valid, so one of them will have a ? instead.

Schedule execution is setup in either owner.scripts or detached.scripts with scheduledExecutions key.

There is some good resources online for helping you generate cron entries Quartz generator help

Note

When loading the cron expression generator, the default expression is define to 0 0 0 ? * * *. To create a expression to execute every seconds, the tab Seconds, Minutes, Hours must be edited.

Examples

See Visualize queries data within charts for the usage of scripts to generate random text at fixed rate