mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-14 00:02:55 +00:00
fix: let one call start only one job across its two surfaces
The card's form and the deployed page's are now live at the same time, and only the card took the manager's submission claim. The call stays pending until `adopt`, a round trip after the page sends its request, so a Run on the card in that window passed the claim and started a second job — with its own arguments, and unmentioned in the chat, which followed the card's. The page takes the same claim before it sends, and hands it back when no job came of it so a failed start can be retried. A successful start needs no release: adopting the job settles the call. Whichever surface is first owns the call; the other sends nothing and says so. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
08554daaa2
commit
5ea8769efe
@@ -300,6 +300,12 @@
|
||||
// pressed under, and a call settled meanwhile — declined, then another proposed for
|
||||
// this same flow — must not be answered with a job it never asked for.
|
||||
const call = pendingRun
|
||||
// One call is one job, and the card's form is live alongside this one: without the
|
||||
// claim, a Run there during the round trip below starts a second.
|
||||
if (call && !call.beginSubmit()) {
|
||||
sendUserToast('This run is already being started from the chat.', true)
|
||||
return
|
||||
}
|
||||
loading = true
|
||||
const scheduledFor = scheduledForStr ? new Date(scheduledForStr).toISOString() : undefined
|
||||
try {
|
||||
@@ -318,6 +324,9 @@
|
||||
if (!call?.adopt(run, args, flow?.schema ?? {}))
|
||||
await onNavigate('/run/' + run + '?workspace=' + workspace)
|
||||
} catch (e) {
|
||||
// No job came of the claim, so hand it back rather than leaving the call unrunnable
|
||||
// on either surface.
|
||||
call?.endSubmit()
|
||||
throw e
|
||||
} finally {
|
||||
loading = false
|
||||
|
||||
@@ -389,6 +389,12 @@
|
||||
// pressed under, and a call settled meanwhile — declined, then another proposed for
|
||||
// this same script — must not be answered with a job it never asked for.
|
||||
const call = pendingRun
|
||||
// One call is one job, and the card's form is live alongside this one: without the
|
||||
// claim, a Run there during the round trip below starts a second.
|
||||
if (call && !call.beginSubmit()) {
|
||||
sendUserToast('This run is already being started from the chat.', true)
|
||||
return
|
||||
}
|
||||
try {
|
||||
runLoading = true
|
||||
const scheduledFor = scheduledForStr ? new Date(scheduledForStr).toISOString() : undefined
|
||||
@@ -420,6 +426,9 @@
|
||||
if (!call?.adopt(run, args, script?.schema ?? {}))
|
||||
await onNavigate('/run/' + run + '?workspace=' + workspace)
|
||||
} catch (err) {
|
||||
// No job came of the claim, so hand it back rather than leaving the call unrunnable
|
||||
// on either surface.
|
||||
call?.endSubmit()
|
||||
sendUserToast(`Could not create job: ${err.body}`, true)
|
||||
} finally {
|
||||
// Not only on failure: a navigation that keeps this component mounted — the run
|
||||
|
||||
@@ -24,4 +24,13 @@ export type PendingRun = {
|
||||
* alone. */
|
||||
adopt: (jobId: string, args: Record<string, any>, schema: Record<string, any>) => boolean
|
||||
decline: () => void
|
||||
/** Claim the call's one job, before starting one. The card's form is live at the same
|
||||
* time as this page's, and the call stays pending until `adopt` — which is a round trip
|
||||
* later — so without this claim a Run on the card in between starts a second job, with
|
||||
* its own arguments and no mention in the chat. False when the other surface claimed it
|
||||
* first; send nothing and say so. */
|
||||
beginSubmit: () => boolean
|
||||
/** Hand the claim back when no job came of it, so the reader can try again. A started
|
||||
* job needs no release: adopting it settles the call. */
|
||||
endSubmit: () => void
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user