From 15f9e9b48fc326aa3d776191aabaed22f4c41e74 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Fri, 10 Jul 2026 15:48:37 +0200 Subject: [PATCH] perf: skip redundant retry-chain job query for successful top-level scripts (#10035) Co-authored-by: Claude Opus 4.8 (1M context) --- .../components/runs/ScriptRetryChain.svelte | 6 +++ .../components/runs/scriptRetryChain.test.ts | 41 +++++++++++++++++++ .../lib/components/runs/scriptRetryChain.ts | 18 ++++++++ 3 files changed, 65 insertions(+) create mode 100644 frontend/src/lib/components/runs/scriptRetryChain.test.ts create mode 100644 frontend/src/lib/components/runs/scriptRetryChain.ts diff --git a/frontend/src/lib/components/runs/ScriptRetryChain.svelte b/frontend/src/lib/components/runs/ScriptRetryChain.svelte index 7ecd104efc..2b2fc2449b 100644 --- a/frontend/src/lib/components/runs/ScriptRetryChain.svelte +++ b/frontend/src/lib/components/runs/ScriptRetryChain.svelte @@ -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: [] } diff --git a/frontend/src/lib/components/runs/scriptRetryChain.test.ts b/frontend/src/lib/components/runs/scriptRetryChain.test.ts new file mode 100644 index 0000000000..066fc2e7f6 --- /dev/null +++ b/frontend/src/lib/components/runs/scriptRetryChain.test.ts @@ -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 { + return { + type: 'CompletedJob', + id: 'j1', + job_kind: 'script', + success: true, + ...overrides + } as Job +} + +function queued(overrides: Partial = {}): 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) + }) +}) diff --git a/frontend/src/lib/components/runs/scriptRetryChain.ts b/frontend/src/lib/components/runs/scriptRetryChain.ts new file mode 100644 index 0000000000..bb2a5e3018 --- /dev/null +++ b/frontend/src/lib/components/runs/scriptRetryChain.ts @@ -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 + ) +}