You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In the Deno, Go, Node, Python, Ruby and Shell ScriptTrigger / CommandsTrigger, edge: true (the default) does nothing: the trigger starts an execution on every poll while the condition keeps matching, instead of only on the not-matching → matching transition. A script that keeps failing floods the flow with executions, one per interval.
Actual Behaviour
The previous result is kept in an in-memory field:
The scheduler rebuilds a polling trigger from the flow definition (and serializes it to a worker) on every evaluation, so lastMatched is always false when evaluate() runs. matched && !lastMatched is therefore always true when the condition matches.
The existing // Known limitation comment says edge mode "may re-fire once after a scheduler restart". What actually happens is much worse: it re-fires on every poll.
Observed with interval: PT10S, edge: true and a script that always exits 1:
Trigger
Executions
Window
ruby.ScriptTrigger (on main)
16
~3 min
perl.ScriptTrigger (PR #446 before 0ba7de7, same code)
22
~4.5 min
perl.CommandsTrigger (PR #446 before 0ba7de7), matching on vars
22
~4.5 min
With edge mode working, each of these should have produced exactly 1 execution.
Expected Behaviour
With edge: true, the trigger emits once when the condition first matches. It stays silent while the condition keeps matching, and emits again only after the condition has stopped matching and then matches again. This state must survive both polls and scheduler restarts.
Reproducer
Start Kestra OSS (kestra/kestra:v1.3.39) with plugin-scripts from main.
Already fixed, to use as the reference:plugin-script-bun, plugin-script-dotnet and plugin-script-powershell store the previous result in the flow's namespace KV store (shouldEmit(...) + edgeStateKey(...)), as the plugin guidelines require for polling-trigger watermarks.
Perl (#446) was fixed the same way in 0ba7de7 before merge: re-running the same two Perl flows on the same instance, each fired once in ~100 s (10 polls) instead of once per poll.
Suggested fix:
Move shouldEmit / edgeStateKey from Bun into a shared helper in plugin-script. This matches the existing TODO: extract shared trigger logic … AbstractScriptTrigger.
Use it from every trigger and remove the lastMatched fields and Known limitation comments.
Add an evaluation-level test per module that calls evaluate() twice on fresh trigger instances built from the same definition, and asserts one emission. Bun's EdgeStateTest is a model.
History: this was already spotted during the reviews of the Bun (#433), .NET (#435) and PowerShell (#436) trigger PRs. Those three moved edge state to the namespace KV store. Moving the other modules over was left as a follow-up that was never tracked; this issue now tracks it.
Summary
In the Deno, Go, Node, Python, Ruby and Shell
ScriptTrigger/CommandsTrigger,edge: true(the default) does nothing: the trigger starts an execution on every poll while the condition keeps matching, instead of only on the not-matching → matching transition. A script that keeps failing floods the flow with executions, one perinterval.Actual Behaviour
The previous result is kept in an in-memory field:
The scheduler rebuilds a polling trigger from the flow definition (and serializes it to a worker) on every evaluation, so
lastMatchedis alwaysfalsewhenevaluate()runs.matched && !lastMatchedis therefore alwaystruewhen the condition matches.The existing
// Known limitationcomment says edge mode "may re-fire once after a scheduler restart". What actually happens is much worse: it re-fires on every poll.Observed with
interval: PT10S,edge: trueand a script that always exits 1:ruby.ScriptTrigger(onmain)perl.ScriptTrigger(PR #446 before 0ba7de7, same code)perl.CommandsTrigger(PR #446 before 0ba7de7), matching on varsWith edge mode working, each of these should have produced exactly 1 execution.
Expected Behaviour
With
edge: true, the trigger emits once when the condition first matches. It stays silent while the condition keeps matching, and emits again only after the condition has stopped matching and then matches again. This state must survive both polls and scheduler restarts.Reproducer
kestra/kestra:v1.3.39) withplugin-scriptsfrommain.The same thing happens with the other affected triggers, for example a Shell
ScriptTriggerrunningexit 1.Logs / Stack Trace
No error is logged. Each poll just produces a new execution whose trigger variables look like this:
Environment
kestra/kestra:v1.3.39, standalone with H2)plugin-scripts1.10.1-SNAPSHOT (mainat a03cd85, plus PR feat(perl): add script commands trigger #446 at f613113 for Perl)Additional Context
Affected, with
AtomicBoolean lastMatchedonmain:plugin-script-deno:ScriptTrigger,CommandsTriggerplugin-script-go:ScriptTrigger,CommandsTriggerplugin-script-node:ScriptTrigger,CommandsTriggerplugin-script-python:AbstractPythonTriggerplugin-script-ruby:ScriptTrigger,CommandsTriggerplugin-script-shell:ScriptTrigger,CommandsTriggerAlready fixed, to use as the reference:
plugin-script-bun,plugin-script-dotnetandplugin-script-powershellstore the previous result in the flow's namespace KV store (shouldEmit(...)+edgeStateKey(...)), as the plugin guidelines require for polling-trigger watermarks.Perl (#446) was fixed the same way in 0ba7de7 before merge: re-running the same two Perl flows on the same instance, each fired once in ~100 s (10 polls) instead of once per poll.
Suggested fix:
shouldEmit/edgeStateKeyfrom Bun into a shared helper inplugin-script. This matches the existingTODO: extract shared trigger logic … AbstractScriptTrigger.lastMatchedfields andKnown limitationcomments.evaluate()twice on fresh trigger instances built from the same definition, and asserts one emission. Bun'sEdgeStateTestis a model.History: this was already spotted during the reviews of the Bun (#433), .NET (#435) and PowerShell (#436) trigger PRs. Those three moved edge state to the namespace KV store. Moving the other modules over was left as a follow-up that was never tracked; this issue now tracks it.
View as Artifact