mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-24 08:01:38 +00:00
perf: skip redundant retry-chain job query for successful top-level scripts (#10035)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
import { goto } from '$lib/navigation'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { resource } from 'runed'
|
||||
import { canSkipRetryChainQuery } from './scriptRetryChain'
|
||||
|
||||
let { job }: { job: Job } = $props()
|
||||
|
||||
@@ -65,6 +66,11 @@
|
||||
// first attempt (the chain root, itself a script). Flow steps also carry
|
||||
// `parent_job`, but their parent is a flow — a non-script root means flow step.
|
||||
if (job.job_kind !== 'script') return { retries: [], handlers: [] }
|
||||
|
||||
// Skip the child-job query when it provably has nothing to show (see
|
||||
// canSkipRetryChainQuery) — this runs on every script run view.
|
||||
if (canSkipRetryChainQuery(job)) return { retries: [], handlers: [] }
|
||||
|
||||
const root = job.parent_job ?? job.id
|
||||
const rootJob = job.id === root ? job : await JobService.getJob({ workspace: ws, id: root })
|
||||
if (rootJob?.job_kind !== 'script') return { retries: [], handlers: [] }
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import type { Job } from '$lib/gen'
|
||||
import { canSkipRetryChainQuery } from './scriptRetryChain'
|
||||
|
||||
// Minimal CompletedJob/QueuedJob factories — canSkipRetryChainQuery only reads
|
||||
// type/parent_job/success/schedule_path, so the rest is cast away.
|
||||
function completed(overrides: Partial<Job> = {}): Job {
|
||||
return {
|
||||
type: 'CompletedJob',
|
||||
id: 'j1',
|
||||
job_kind: 'script',
|
||||
success: true,
|
||||
...overrides
|
||||
} as Job
|
||||
}
|
||||
|
||||
function queued(overrides: Partial<Job> = {}): Job {
|
||||
return { type: 'QueuedJob', id: 'j1', job_kind: 'script', ...overrides } as Job
|
||||
}
|
||||
|
||||
describe('canSkipRetryChainQuery', () => {
|
||||
it('skips a successful, non-scheduled, top-level script (nothing to show)', () => {
|
||||
expect(canSkipRetryChainQuery(completed())).toBe(true)
|
||||
})
|
||||
|
||||
it('does NOT skip a failed script — it may have retry attempts', () => {
|
||||
expect(canSkipRetryChainQuery(completed({ success: false }))).toBe(false)
|
||||
})
|
||||
|
||||
it('does NOT skip a chain member (parent_job set) — e.g. a successful final retry', () => {
|
||||
expect(canSkipRetryChainQuery(completed({ parent_job: 'root' }))).toBe(false)
|
||||
})
|
||||
|
||||
it('does NOT skip a schedule-triggered success — it may have a recovery handler', () => {
|
||||
expect(canSkipRetryChainQuery(completed({ schedule_path: 'f/s/daily' }))).toBe(false)
|
||||
})
|
||||
|
||||
it('does NOT skip a still-running (queued) job — outcome not yet known', () => {
|
||||
expect(canSkipRetryChainQuery(queued({ running: true }))).toBe(false)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,18 @@
|
||||
import type { Job } from '$lib/gen'
|
||||
|
||||
/**
|
||||
* A successful, non-scheduled, top-level script can have neither retry attempts
|
||||
* (retries only spawn after a failure, so the first attempt would not be
|
||||
* `success`) nor schedule handlers (they only fire for schedule triggers, i.e.
|
||||
* when `schedule_path` is set). Its child-job (`parent_job = ?`) query would
|
||||
* always come back empty, so it can be skipped — this runs on every script run
|
||||
* view, so avoiding the round-trip on the common success path matters.
|
||||
*/
|
||||
export function canSkipRetryChainQuery(job: Job): boolean {
|
||||
return (
|
||||
job.type === 'CompletedJob' &&
|
||||
job.parent_job == null &&
|
||||
job.success === true &&
|
||||
job.schedule_path == null
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user