Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Overview

This document provides information on the execution process of Script Engine (Reference) manages the execution, synchronization, and optimization of all scripts, tasks, and expressions within the platform. It includes insights into how scripts and tasks interact with device protocols, facilitating communication and data synchronization in distributed network environments. In this section, you will find details on script task execution, diagnostic information, data synchronization, and pre-loading objects.On FrameworX runtime environment.

Advanced Topic: This document provides deep technical insight into the Scripts module execution engine. Most solutions don't require this level of understanding - the default engine behavior handles typical automation requirements automatically.

In this page:

Table of Contents
maxLevel

3

2
minLevel2
indent10px
excludeSteps
stylenone

ScriptTasks

Each ScriptTask is a thread running the code content. It can be executed by Trigger (when a tag value changes) or Period (scheduled time to run cyclically).

The management of execution is handled by the Runtime engine. As there is no limitation on the quantity or complexity of the scripts, verifying the CPU allocation is necessary when deploying a solution.

Even if you do not include .NET Exception control in your code, each ScriptTask has a Try/Catch protection automatically added around it, ensuring that no script created within the solution may compromise the system.

Diagnostic Information

Each execution of ScriptTask is monitored by the Runtime. Iis possible to know:

  • Last execution (datetime).
  • Last CPU time (duration to execute the Script Task).
  • Peak of Last CPU time.
  • Execution count.
  • State (Task running or idle).
  • Code exceptions.

Those properties are exposed in the object model, like Script.Task.Task1.State. Refer to the Namespace API (Reference) for the list of all properties.
Some of those properties are automatically show on the Scripts Monitor (Reference) page.

Data Synchronization

When a ScriptTask is created utilizing certain functionalities or expressions, data synchronization may be implemented to ensure data integrity and consistency between the server and various modules and processes that may be running on remote computers.

Our platform, designed to enable distributed applications, maintains connections between different modules (scripts, datasets, reports, UI clients, etc.) and remote client computers, orchestrating data synchronization and preventing bottlenecks, thereby guaranteeing that the most recent tag values are synchronized correctly.

In the distributed setup, there exists a server-module connection that operates across multiple computers. This connection facilitates data synchronization between the server and various modules, maintaining an internal queue that holds data pending synchronization. Each tag can occupy a single position within this queue.

In instances where a module modifies a tag value already present in the queue, only the value is updated. This system ensures the efficient management of rapidly changing tag values by prioritizing the synchronization of the latest values, thus preventing queue overflow and memory leaks.

However, specific situations necessitate the synchronization of all tag changes. In such cases, the 'RaiseAllChanges' property must be activated. It is essential to exercise caution with this function, as it might increase the synchronization queue, potentially leading to significant memory usage on the computer, especially when scripting tasks or CodeBehind utilize loops to alter tag values repeatedly.

In some advanced and large applications, when starting a remote client process, you may want to synchronize all data before starting your Operator Displays. This is accomplished by the Preload method in the Toolkit, which is described in the next topic.

Timeout

As previously noted, a 2-minute timeout exists within the server-module connection. If the synchronization of a large object, like a DataTable tag, exceeds this period, connection and synchronization issues may arise, affecting the stability of the module connections.

Solution Shutdown

During a solution shutdown, each module pauses to complete all ongoing executions. This process includes clearing the synchronization queue to prevent data loss. Following the completion of all executions and queue clearance, modules disconnect, signaling the server to initiate the shutdown process.

Pre-Loading Objects

Pre-loading objects serves as a facilitating mechanism in data synchronization, ensuring that objects are synchronized before their initial utilization in scripts or screens. This pre-loading can occur automatically or can be customized, enabling faster script execution and mitigating potential delays due to real-time data synchronization.

Upon the first usage of an object, it is enlisted in the synchronization list, triggering server notifications to facilitate client data synchronization. The pre-loading process aims to incorporate objects into the synchronization list prior to their initial usage, enhancing execution speed in synchronization-dependent contexts, such as scripts. Manual intervention can use the Toolkit Preload() method, but it is important to emphasize that it is very rare for this scenario to be necessary. For most solutions, including large ones, the automatic pre-loads executed by the platform handle the requirements.

Now, let's delve into the functioning of the automatic pre-load:

There are two contexts of use: scripts and screens. Only after finishing the pre-load in scripts are the "Script Startup" and other scripts released. In screens, the pre-load occurs simultaneously with the display. Unlike scripts, in screens, it's acceptable to show an initial value that can later be updated after receiving the synchronized value from the server.

There are two types of automatic pre-loads:

  1. Based on Cache: During the first execution, since there is no cache, the pre-load is swift. Upon closing the module, the cache of the used objects is saved. On subsequent startups, the pre-load occurs from this cache. Hence, depending on interactions, the number of objects in the cache can vary, stabilizing as the objects are used more often. For example, if a module has three different scripts with three distinct tags, the maximum cache consists of these three tags. However, if only two scripts were executed upon closing the module, only two tags will be in the cache. It's crucial to note that changes in the project or module invalidate the cache, starting from scratch. The completion of the pre-load is indicated by a "marker" at the end of the list.

  2. By Anticipation: During the module's execution, the system tries to anticipate the use of objects, increasing the likelihood that they are already in memory when needed. However, there are unpredictable situations, such as the use of Tk.GetObjectValue or dynamic references. If a script attempts to access a tag not yet synchronized, it pauses until synchronization occurs. For this reason, the cache-based method is often more effective after the first execution, as even dynamic objects enter the cache.

Additionally, there's customized pre-loading. Here, the user can trigger pre-load methods to force the addition of an object to the list, even if it is not in the cache or hasn't been detected by the system. This method is only executed after completing the cache-based pre-load, and it is commonly added in the Task.Startup.

Therefore, the system should be capable of pre-loading in the long run for a completed project that doesn't change by itself, which should be sufficient. However, the user can input a pre-load of objects that they insist should always be loaded, regardless of whether it's the system's first time running or not. The goal of the pre-load is not to improve the startup time; on the contrary, the more objects in the cache and pre-load, the slower the startup will be. Conversely, after initialization, there is a higher chance of achieving better performance during the first execution of certain tasks or scripts.


Overview

The Script Engine orchestrates:

  • Multi-threaded task execution
  • Data synchronization across distributed systems
  • Memory management and caching
  • Exception protection and diagnostics
  • Pre-loading and performance optimization

Understanding the engine helps when:

  • Optimizing large-scale solutions
  • Debugging complex timing issues
  • Managing distributed architectures
  • Implementing high-performance scripting

Task Execution Model

Threading Architecture

Each Script Task runs in its own managed thread:

  • Independent execution: Tasks don't block each other
  • Thread pool management: Automatic allocation and recycling
  • CPU monitoring: Track execution time per task
  • Exception isolation: Failures don't cascade

csharp

// Each task automatically wrapped with:
try 
{
    // Your task code executes here
    // In its own thread context
}
catch (Exception ex)
{
    // Automatic exception handling
    // Logged but doesn't crash system
}

Execution Triggers

Trigger TypeDescriptionThread Behavior
Tag ChangeExecutes when tag value changesNew thread per change
PeriodRuns at fixed intervalsReuses thread if available
StartupRuns once at module startPriority thread
ExpressionInline executionThread pool shared

CPU Management

The engine monitors CPU usage to prevent system overload:

  • Tasks yielding excessive CPU are flagged
  • Long-running tasks don't block others
  • Automatic thread priority adjustment

Diagnostic Properties

Access runtime metrics via @Script.Task.[TaskName] namespace:

PropertyTypeDescription
LastExecutionDateTimeWhen task last ran
LastCPUTimeTimeSpanDuration of last execution
PeakCPUTimeTimeSpanMaximum execution time recorded
ExecutionCountIntegerTotal number of executions
StateEnumRunning, Idle, or Error
LastExceptionStringMost recent error message

Monitor these in:

  • [Scripts Monitor (Reference)] - Real-time dashboard
  • PropertyWatch - During debugging
  • Custom displays - For operator visibility

Data Synchronization

Distributed Architecture

The engine maintains data consistency across:

  • Server (TServer.exe) - Central data authority
  • Clients (TRichClient.exe, Web) - Remote displays
  • Modules - Scripts, Datasets, Reports running remotely

Synchronization Queue

Each server-module connection maintains an internal queue:

[Server] → [Queue] → [Module/Client]
    Tag Updates
    Method Calls
    State Changes

Queue Optimization:

  • Each tag occupies ONE queue position
  • Rapid changes update value in-place
  • Prevents memory overflow
  • Latest value prioritized

RaiseAllChanges Property

<ac:structured-macro ac:name="warning"> ac:rich-text-body Use with Caution: Enabling RaiseAllChanges forces ALL intermediate values into the queue, potentially causing:

  • Memory exhaustion
  • Queue overflow
  • Performance degradation </ac:rich-text-body> </ac:structured-macro>

Enable only when:

  • Audit trail requires all values
  • Historical accuracy critical
  • Processing can handle volume

csharp

// Example of potential issue
for (int i = 0; i < 10000; i++)
{
    @Tag.Counter = i;  // With RaiseAllChanges, queues 10,000 updates!
}

Synchronization Timeout

  • Default: 2 minutes
  • Impact: Large objects (DataTables) must sync within timeout
  • Failure: Connection drops, requires reconnection

Shutdown Sequence

  1. Module receives shutdown signal
  2. Current executions complete
  3. Synchronization queue flushes
  4. Module disconnects
  5. Server proceeds with shutdown

Pre-Loading System

Automatic Pre-Loading

The engine implements two pre-loading strategies:

1. Cache-Based Pre-Loading

First Execution:

  • No cache exists
  • Minimal pre-load
  • Objects cached as used

Subsequent Executions:

  • Load from saved cache
  • Contains previously used objects
  • Stabilizes over time

Cache Invalidation:

  • Project changes clear cache
  • Module updates reset cache
  • Starts fresh after changes

2. Anticipatory Pre-Loading

During execution, the engine predicts object usage:

  • Analyzes script patterns
  • Pre-fetches likely objects
  • Reduces first-access delay

Limitations:

  • Cannot predict dynamic references
  • TK.GetObjectValue() unpredictable
  • Conditional logic uncertain

Manual Pre-Loading

Force objects into memory before use:

csharp

// In ServerStartup task
TK.PreloadTags("Critical.*");  // Preload all Critical tags
TK.PreloadObject(@Alarm.Area1); // Preload specific alarm area

Execution Order:

  1. Cache-based pre-load completes
  2. Manual pre-load executes
  3. ServerStartup task runs
  4. Other tasks enabled

Pre-Loading Trade-offs

AspectMore Pre-LoadingLess Pre-Loading
Startup TimeSlowerFaster
First ExecutionFasterMay pause for sync
Memory UsageHigherLower
PredictabilityConsistentVariable

Performance Optimization

Script Task Optimization

  1. Minimize Blocking Operations

csharp

   // Avoid
   Thread.Sleep(5000);  // Blocks thread
   
   // Prefer
   @Tag.DelayedAction = true;  // Event-driven
  1. Batch Tag Updates

csharp

   // Inefficient
   for (int i = 0; i < 100; i++)
       @Tag["Item" + i] = value;
   
   // Efficient
   var updates = new Dictionary<string, object>();
   // Prepare all updates
   TK.SetMultipleTags(updates);  // Single sync
  1. Use Appropriate Triggers
    • Change-based for reactive logic
    • Time-based for polling
    • Avoid high-frequency triggers

Expression Optimization

  • Simple calculations only
  • Complex logic in Script Classes
  • Minimize tags per expression
  • Use TIF instead of IIF for methods

Memory Management

Monitor and manage:

  • Cache size growth
  • Queue depth
  • Thread count
  • Object references

Advanced Scenarios

Large DataTable Synchronization

csharp

// Split large tables to avoid timeout
var chunks = TK.SplitDataTable(largeTable, 1000);
foreach (var chunk in chunks)
{
    @Tag.PartialData = chunk;
    TK.Sleep(100);  // Allow queue processing
}

Dynamic Object Access

csharp

// Pre-load dynamic references
string tagName = GetDynamicTagName();
TK.PreloadTag(tagName);  // Force sync
var value = TK.GetObjectValue("Tag." + tagName);

High-Frequency Updates

csharp

// Buffer rapid changes
private DateTime lastUpdate;
private double bufferedValue;

public void ProcessHighFrequency(double value)
{
    bufferedValue = value;
    if ((DateTime.Now - lastUpdate).TotalMilliseconds > 100)
    {
        @Tag.Output = bufferedValue;
        lastUpdate = DateTime.Now;
    }
}

Troubleshooting

Task Not Executing

  • Check State property
  • Verify trigger conditions
  • Review LastException
  • Monitor CPU usage

Synchronization Issues

  • Check queue depth
  • Verify timeout settings
  • Review network latency
  • Monitor memory usage

Performance Problems

  • Profile with Scripts Monitor
  • Check PeakCPUTime
  • Review pre-loading strategy
  • Optimize synchronization

Best Practices

  1. Let the engine manage threads - Don't create manual threads
  2. Trust automatic pre-loading - Manual intervention rarely needed
  3. Monitor diagnostics - Use built-in properties
  4. Design for distribution - Consider network delays
  5. Test at scale - Verify with production data volumes
  6. Profile before optimizing - Measure actual bottlenecks

In this section...

Page Tree
root@parent
spaces93DRAF

In this section:

Page Tree
rootV10:@parent
spacesV10