From 39b5242fc28a67fa073e186333c4c4495482e39e Mon Sep 17 00:00:00 2001 From: Dan Sutton Date: Mon, 13 Jul 2026 15:49:45 +0100 Subject: [PATCH] perf(webapp): avoid unindexed fileId scan in get-background-worker-by-version The endpoint loaded each file's tasks via the files.tasks relation, which queries BackgroundWorkerTask by the unindexed fileId column and sequential-scans a very large table for every request. Group task slugs by fileId in memory from the tasks that are already loaded via the indexed workerId relation, and drop the files.tasks include. The response shape is unchanged. --- ...ackground-worker-version-endpoint-tasks.md | 6 +++++ ...ef.background-workers.$envSlug.$version.ts | 25 +++++++++++-------- 2 files changed, 21 insertions(+), 10 deletions(-) create mode 100644 .server-changes/background-worker-version-endpoint-tasks.md diff --git a/.server-changes/background-worker-version-endpoint-tasks.md b/.server-changes/background-worker-version-endpoint-tasks.md new file mode 100644 index 00000000000..2499bcc3a05 --- /dev/null +++ b/.server-changes/background-worker-version-endpoint-tasks.md @@ -0,0 +1,6 @@ +--- +area: webapp +type: improvement +--- + +Speed up retrieving a background worker by version. The endpoint no longer runs a slow lookup that scanned the full task table for large deployments; it now reuses data it already loads, so the response is the same but returns much faster. diff --git a/apps/webapp/app/routes/api.v1.projects.$projectRef.background-workers.$envSlug.$version.ts b/apps/webapp/app/routes/api.v1.projects.$projectRef.background-workers.$envSlug.$version.ts index 72c45492794..99e1dcc9ac5 100644 --- a/apps/webapp/app/routes/api.v1.projects.$projectRef.background-workers.$envSlug.$version.ts +++ b/apps/webapp/app/routes/api.v1.projects.$projectRef.background-workers.$envSlug.$version.ts @@ -45,15 +45,7 @@ export async function loader({ params, request }: LoaderFunctionArgs) { }, include: { tasks: true, - files: { - include: { - tasks: { - select: { - slug: true, - }, - }, - }, - }, + files: true, }, }); @@ -61,6 +53,19 @@ export async function loader({ params, request }: LoaderFunctionArgs) { return json({ error: "Background worker not found" }, { status: 404 }); } + // Group task slugs by fileId from the already-loaded tasks (which are fetched + // via the indexed workerId relation) instead of loading files.tasks, which + // queries BackgroundWorkerTask by the unindexed fileId column. + const taskSlugsByFileId = new Map>(); + for (const task of backgroundWorker.tasks) { + if (!task.fileId) { + continue; + } + const slugs = taskSlugsByFileId.get(task.fileId) ?? new Set(); + slugs.add(task.slug); + taskSlugsByFileId.set(task.fileId, slugs); + } + return json({ id: backgroundWorker.friendlyId, version: backgroundWorker.version, @@ -82,7 +87,7 @@ export async function loader({ params, request }: LoaderFunctionArgs) { filePath: file.filePath, contentHash: file.contentHash, contents: decompressContent(file.contents), - tasks: Array.from(new Set(file.tasks.map((task) => task.slug))), + tasks: Array.from(taskSlugsByFileId.get(file.id) ?? []), })), }); } catch (error) {