Skip to content

Commit dfe36b4

Browse files
committed
perf(webapp): stop hydrating run metadata on the list unless a column needs it
metadata/metadataType were selected for every runs-list row on every request but nothing on the list rendered them (the replay dialog fetches metadata via its own loader). Gate them behind a metadata smart column, like payload/output, so they are only hydrated when referenced. The public runs-list API still returns metadata, so it now requests it explicitly via the columns option.
1 parent 07bf4bd commit dfe36b4

5 files changed

Lines changed: 17 additions & 19 deletions

File tree

apps/webapp/app/components/runs/v3/runColumns.test.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@ describe("deriveRunSelect", () => {
3232
"queueTimestamp",
3333
"delayUntil",
3434
"scheduleId",
35-
"metadata",
36-
"metadataType",
3735
"taskIdentifier",
3836
"machinePreset",
3937
"queue",
@@ -43,12 +41,14 @@ describe("deriveRunSelect", () => {
4341
}
4442
});
4543

46-
it("does not hydrate the large blobs unless a smart column references them", () => {
44+
it("does not hydrate the source blobs unless a smart column references them", () => {
4745
const select = deriveRunSelect(["task", "status", "tags"], []);
4846
expect(select.payload).toBeUndefined();
4947
expect(select.payloadType).toBeUndefined();
5048
expect(select.output).toBeUndefined();
5149
expect(select.outputType).toBeUndefined();
50+
expect(select.metadata).toBeUndefined();
51+
expect(select.metadataType).toBeUndefined();
5252
});
5353

5454
it("adds payload/output fields only for referenced smart sources", () => {
@@ -62,7 +62,8 @@ describe("deriveRunSelect", () => {
6262
expect(both.outputType).toBe(true);
6363
});
6464

65-
it("references metadata from the always-selected set without a smart source", () => {
65+
it("adds metadata fields only when a metadata smart column references them", () => {
66+
expect(deriveRunSelect([], []).metadata).toBeUndefined();
6667
const select = deriveRunSelect([], ["metadata"]);
6768
expect(select.metadata).toBe(true);
6869
expect(select.metadataType).toBe(true);

apps/webapp/app/components/runs/v3/runColumns.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,11 @@ export type StandardColumnDef = {
4747

4848
/**
4949
* The scalar fields the shared presenter always maps into its stable output,
50-
* regardless of which columns show. Because the presenter contract is fixed and
51-
* these are all small single-row columns (no DB win from narrowing them), the
52-
* select currently gates only the large blobs: payload/output are added solely
53-
* when a smart column references them. Shrinking this set to a behaviour-only
54-
* floor later is a change here plus defensive presenter mapping, not an API
55-
* change to `deriveRunSelect`.
50+
* regardless of which columns show. These are all small single-row columns with
51+
* no DB win from narrowing, so the select keeps them for a stable contract and
52+
* gates only the large blobs: payload, output, and metadata are added solely
53+
* when a smart column references them (metadata is display-only on the list, so
54+
* there is no reason to hydrate it for every row otherwise).
5655
*/
5756
const ALWAYS_SELECTED_FIELDS = [
5857
"id",
@@ -81,8 +80,6 @@ const ALWAYS_SELECTED_FIELDS = [
8180
"depth",
8281
"rootTaskRunId",
8382
"batchId",
84-
"metadata",
85-
"metadataType",
8683
"machinePreset",
8784
"queue",
8885
"workerQueue",

apps/webapp/app/presenters/v3/ApiRunListPresenter.server.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ export class ApiRunListPresenter extends BasePresenter {
183183
return this.trace("call", async (span) => {
184184
const options: RunListOptions = {
185185
projectId: project.id,
186+
columns: { visibleStandardIds: [], smartSources: ["metadata"] },
186187
};
187188

188189
// pagination
@@ -310,7 +311,7 @@ export class ApiRunListPresenter extends BasePresenter {
310311
const metadata = await parsePacket(
311312
{
312313
data: run.metadata ?? undefined,
313-
dataType: run.metadataType,
314+
dataType: run.metadataType ?? "application/json",
314315
},
315316
{
316317
filteredKeys: ["$$streams", "$$streamsVersion", "$$streamsBaseUrl"],

apps/webapp/app/services/runsRepository/clickhouseRunsRepository.server.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@ const LIST_RUN_DEFAULT_SELECT = {
5151
depth: true,
5252
rootTaskRunId: true,
5353
batchId: true,
54-
metadata: true,
55-
metadataType: true,
5654
machinePreset: true,
5755
queue: true,
5856
workerQueue: true,

apps/webapp/app/services/runsRepository/runsRepository.server.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,6 @@ export type ListedRun = Prisma.TaskRunGetPayload<{
119119
depth: true;
120120
rootTaskRunId: true;
121121
batchId: true;
122-
metadata: true;
123-
metadataType: true;
124122
machinePreset: true;
125123
queue: true;
126124
workerQueue: true;
@@ -129,13 +127,16 @@ export type ListedRun = Prisma.TaskRunGetPayload<{
129127
};
130128
}> & {
131129
/**
132-
* Large source blobs hydrated only when a smart column references them (see
133-
* `runSelect`). Absent from the default list select.
130+
* Source blobs hydrated only when a smart column references them (see
131+
* `runSelect`). Absent from the default list select; metadata is display-only
132+
* on the list, payload/output can be large.
134133
*/
135134
payload?: string;
136135
payloadType?: string;
137136
output?: string | null;
138137
outputType?: string;
138+
metadata?: string | null;
139+
metadataType?: string;
139140
};
140141

141142
export type ListRunsOptions = RunListInputOptions &

0 commit comments

Comments
 (0)