feat(runtime): per-script execution timeout overriding the global default (#9)

Spec promised a per-script timeout but only the global ScriptExecutionTimeoutSeconds
existed. Add nullable TemplateScript.ExecutionTimeoutSeconds threaded through EF +
flattening (ResolvedScript) to ScriptExecutionActor/AlarmExecutionActor, which use
perScript ?? global for the execution CTS. Includes the EF migration for the new column.
This commit is contained in:
Joseph Doherty
2026-06-15 14:40:38 -04:00
parent 00304a26e6
commit 3edef09f51
22 changed files with 2094 additions and 17 deletions
@@ -141,7 +141,8 @@ public class DiffService
a.TriggerConfiguration == b.TriggerConfiguration &&
a.ParameterDefinitions == b.ParameterDefinitions &&
a.ReturnDefinition == b.ReturnDefinition &&
a.MinTimeBetweenRuns == b.MinTimeBetweenRuns;
a.MinTimeBetweenRuns == b.MinTimeBetweenRuns &&
a.ExecutionTimeoutSeconds == b.ExecutionTimeoutSeconds;
/// <summary>
/// Compares two <see cref="ConnectionConfig"/> instances for equality across
@@ -830,6 +830,10 @@ public class FlatteningService
ParameterDefinitions = script.ParameterDefinitions,
ReturnDefinition = script.ReturnDefinition,
MinTimeBetweenRuns = script.MinTimeBetweenRuns,
// M2.5 (#9): per-script timeout rides along on the winning row.
// Scripts inherit/override at whole-row granularity (no per-field
// merge), so this follows the same rule as the script body/MinTime.
ExecutionTimeoutSeconds = script.ExecutionTimeoutSeconds,
Source = source
};
idByName[script.Name] = script.Id;
@@ -83,7 +83,10 @@ public class RevisionHashService
TriggerConfiguration = s.TriggerConfiguration,
ParameterDefinitions = s.ParameterDefinitions,
ReturnDefinition = s.ReturnDefinition,
MinTimeBetweenRunsTicks = s.MinTimeBetweenRuns?.Ticks
MinTimeBetweenRunsTicks = s.MinTimeBetweenRuns?.Ticks,
// M2.5 (#9): include the per-script timeout so a change to it
// is detected as a configuration change (staleness/redeploy).
ExecutionTimeoutSeconds = s.ExecutionTimeoutSeconds
})
.ToList(),
Connections = configuration.Connections is { Count: > 0 }
@@ -244,6 +247,10 @@ public class RevisionHashService
/// </summary>
public string Code { get; init; } = string.Empty;
/// <summary>
/// M2.5 (#9): the per-script execution timeout in seconds (null = global).
/// </summary>
public int? ExecutionTimeoutSeconds { get; init; }
/// <summary>
/// Whether the script is locked.
/// </summary>
public bool IsLocked { get; init; }
@@ -17,7 +17,7 @@ namespace ZB.MOM.WW.ScadaBridge.TemplateEngine;
/// Override granularity:
/// - Attributes: Value and Description overridable; DataType and DataSourceReference fixed.
/// - Alarms: Priority, TriggerConfiguration, Description, OnTriggerScript overridable; Name and TriggerType fixed.
/// - Scripts: Code, TriggerConfiguration, MinTimeBetweenRuns, params/return overridable; Name fixed.
/// - Scripts: Code, TriggerConfiguration, MinTimeBetweenRuns, ExecutionTimeoutSeconds, params/return overridable; Name fixed.
/// - Lock flag applies to the entire member (attribute/alarm/script).
/// </summary>
public static class LockEnforcer
@@ -687,6 +687,8 @@ public class TemplateService
existing.TriggerType = proposed.TriggerType;
existing.TriggerConfiguration = proposed.TriggerConfiguration;
existing.MinTimeBetweenRuns = proposed.MinTimeBetweenRuns;
// M2.5 (#9): per-script execution timeout is an overridable field.
existing.ExecutionTimeoutSeconds = proposed.ExecutionTimeoutSeconds;
existing.ParameterDefinitions = proposed.ParameterDefinitions;
existing.ReturnDefinition = proposed.ReturnDefinition;
existing.IsLocked = proposed.IsLocked;
@@ -1013,6 +1015,7 @@ public class TemplateService
ParameterDefinitions = script.ParameterDefinitions,
ReturnDefinition = script.ReturnDefinition,
MinTimeBetweenRuns = script.MinTimeBetweenRuns,
ExecutionTimeoutSeconds = script.ExecutionTimeoutSeconds,
IsInherited = true,
LockedInDerived = false,
});