mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-13 08:02:47 +00:00
fix(schedules): load the runnable by its own kind, and let a newer config win
The kind was adopted after the fetch, so a flow-backed schedule was looked up through ScriptService: a 404 into the swallowed catch, and a form with no runnable — no arguments schema and no runnable actions. The hosted view cannot say which kind it is either, since it only knows the schedule's path. And applying a config awaits that fetch halfway through its assignments, with nothing to stop an older application finishing over a newer one — two chat writes landing close together could leave the form half of each. Each application now supersedes the last, and a superseded one stops rather than writing on. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KcyBRxE8j3ujCYkum9KrC4
This commit is contained in:
co-authored by
Claude Opus 5
parent
b0d7224b58
commit
f9825b14ea
@@ -472,15 +472,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function loadScript(p: string | undefined): Promise<void> {
|
||||
async function loadScript(p: string | undefined, generation?: number): Promise<void> {
|
||||
if (p) {
|
||||
runnable = undefined
|
||||
try {
|
||||
if (is_flow) {
|
||||
runnable = await FlowService.getFlowByPath({ workspace: wsId!, path: p })
|
||||
} else {
|
||||
runnable = await ScriptService.getScriptByPath({ workspace: wsId!, path: p })
|
||||
}
|
||||
const loaded = is_flow
|
||||
? await FlowService.getFlowByPath({ workspace: wsId!, path: p })
|
||||
: await ScriptService.getScriptByPath({ workspace: wsId!, path: p })
|
||||
// Superseded while the request was in flight: this is the runnable of a
|
||||
// config the form has already moved off.
|
||||
if (generation === undefined || generation === applyGeneration) runnable = loaded
|
||||
} catch (err) {}
|
||||
} else {
|
||||
runnable = undefined
|
||||
@@ -603,7 +604,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Every application of a config supersedes the one before it — a chat write
|
||||
// arriving through the draft sync, a load, a draft overlay. `loadScript` awaits
|
||||
// halfway through the assignments, so without this an older apply finishes last
|
||||
// and writes its half of the form over the newer one.
|
||||
let applyGeneration = 0
|
||||
|
||||
async function loadScheduleCfg(cfg: Record<string, any>): Promise<void> {
|
||||
const generation = ++applyGeneration
|
||||
loading = true
|
||||
|
||||
cronVersion = cfg.cron_version ?? 'v2'
|
||||
@@ -619,9 +627,13 @@
|
||||
labels = cfg.labels ?? undefined
|
||||
description = cfg.description ?? ''
|
||||
script_path = cfg.script_path ?? ''
|
||||
await loadScript(script_path)
|
||||
|
||||
// Before the fetch, which reads it: a flow-backed schedule looked up through
|
||||
// ScriptService 404s into the swallowed catch below, leaving the form with no
|
||||
// runnable — no arguments schema, no runnable actions.
|
||||
itemKind = cfg.is_flow ? 'flow' : 'script'
|
||||
await loadScript(script_path, generation)
|
||||
if (generation !== applyGeneration) return
|
||||
|
||||
no_flow_overlap = cfg.no_flow_overlap ?? false
|
||||
wsErrorHandlerMuted = cfg.ws_error_handler_muted ?? false
|
||||
retry = cfg.retry
|
||||
|
||||
Reference in New Issue
Block a user