Skip to content

Host Trigger

Mick edited this page Jul 7, 2026 · 1 revision

Host Trigger

Host Trigger is the main v1.10.0 runtime feature. It lets a host application keep a RuleScript runtime alive, enqueue named events, and let script-defined handlers process those events in order.

Use Host Trigger when a script should react to external activity such as messages, UI events, device scans, workflow state changes, or automation callbacks. Use Execute or ExecuteAsync when a script should run once and finish.

Script Shape

A Host Trigger script has two parts:

  • one or more functions marked with @HostTrigger("Name")
  • a parallel block containing a trigger task with dispatch;
@HostTrigger("LotArrived")
function OnLotArrived(lotId: string) -> void:
    Print("lot arrived: " + lotId);
    return;
endfunction

parallel:
    trigger task:
        dispatch;
    endtask
endparallel

The trigger name is the host-visible name. The function name is still the script function name and appears in symbol metadata.

Start, Trigger, Stop

var engine = new RuleScriptEngine
{
    ExecutionTimeoutEnabled = false
};

var runtime = engine.CreateRuntime(script);
var running = runtime.StartAsync();

RuleScriptTriggerReceipt receipt =
    await runtime.TriggerAsync("LotArrived", ["LOT-001"]);

await runtime.StopAsync();
await running;

StartAsync starts execution and returns the runtime task. TriggerAsync accepts a trigger request into the dispatcher queue and returns a receipt with SequenceId and Name. StopAsync cancels the runtime, completes dispatching, and waits for shutdown.

Runtime State

RuleScriptRuntime.State reports:

State Meaning
Created Runtime has been created but not started.
Running Runtime is executing and can accept trigger requests.
Stopping Stop has been requested.
Stopped Runtime completed normally or was stopped.
Faulted Runtime ended because of an error.

TriggerAsync throws when:

  • the runtime is not running
  • the script has no active trigger task dispatcher
  • the requested Host Trigger name is not registered
  • cancellation is requested before the request is queued

Discover Triggers Before Running

Analyze source to discover trigger metadata without executing the script:

RuleScriptAnalysisResult analysis = engine.Analyze(script);

foreach (var trigger in analysis.HostTriggers)
{
    Console.WriteLine(trigger.HostTriggerMetadata?.Name);
    Console.WriteLine(trigger.Name);
    Console.WriteLine(trigger.Signature);
}

Runtime instances expose the same trigger symbols:

var runtime = engine.CreateRuntime(script);

foreach (var trigger in runtime.HostTriggers)
{
    Console.WriteLine($"{trigger.HostTriggerMetadata?.Name}: {trigger.Signature}");
}

Each trigger is a RuleScriptFunctionSymbol. Its HostTriggerMetadata contains the host-visible name from @HostTrigger("Name").

Trigger Dispatcher Rules

trigger task is only valid directly inside a parallel block.

parallel:
    task:
        Print("startup work");
    endtask

    trigger task:
        dispatch;
    endtask
endparallel

The dispatcher waits for one request, dispatches it to the best matching Host Trigger function, then waits again. Requests are processed in FIFO order.

dispatch; is special inside a trigger task. Analysis does not treat it as an undefined variable in that position.

Typed Trigger Functions

Host Trigger functions are normal user functions with metadata. They can use typed parameters and explicit return types:

@HostTrigger("AlarmRaised")
function AlarmRaised(code: string, severity: number) -> void:
    Print(code + ": " + ToString(severity));
    return;
endfunction

Overload resolution follows the same rules as typed user functions. The host supplies arguments through TriggerAsync.

Runtime From Files

var engine = new RuleScriptEngine
{
    WorkingDirectory = @"C:\rules",
    ExecutionTimeoutEnabled = false
};

var runtime = engine.CreateRuntimeFromFile("main");

CreateRuntimeFromFile follows the same project-loading behavior as ExecuteFile: WorkingDirectory, ScriptFileExtension, ImportResolver, and imports all apply.

Debugging Host Trigger Runtimes

RuleScriptDebugSession can create trigger runtimes while preserving breakpoints, stepping, runtime events, and snapshots:

var engine = new RuleScriptEngine
{
    WorkingDirectory = @"C:\rules",
    ExecutionTimeoutEnabled = false
};

engine.AddBreakpoint("main.rules", 12);

var session = new RuleScriptDebugSession(engine);
var runtime = session.CreateRuntimeFromFile("main.rules");

var running = runtime.StartAsync();
await runtime.TriggerAsync("LotArrived", ["LOT-001"]);

var pause = await session.WaitForPauseAsync();
Console.WriteLine(pause.Location.Line);
session.Continue();

await runtime.StopAsync();
await running;

Compatibility Notes

  • Existing Execute, ExecuteAsync, ExecuteFile, and ExecuteFileAsync behavior is unchanged.
  • Existing Host Functions remain host-callable from scripts; Host Trigger functions are script handlers invoked by a runtime dispatcher.
  • Host Trigger requests are queued by the host, not invoked directly from a host thread.
  • A long-running Host Trigger runtime commonly disables ExecutionTimeoutEnabled; keep cancellation and StopAsync in the host lifecycle.
  • Registered Host Function thread-safety checks still apply to ordinary parallel task execution.

Clone this wiki locally