Skip to content

Commit f59abe7

Browse files
committed
refactor(webapp): hydrate parent-model TaskRun reads through the run store
Decompose the three reads that pulled TaskRun in through a parent model's relation include (alert, batch results, attempt dependencies): query the parent without the include, hydrate the run(s) via RunStore in a single batched read, and stitch them back. Preserves field selection, ordering, null handling and the query client. Adds container-backed tests for the batch-results and cancel-dependencies paths.
1 parent 126b05f commit f59abe7

5 files changed

Lines changed: 606 additions & 32 deletions

File tree

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

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { BatchTaskRunExecutionResult } from "@trigger.dev/core/v3";
2-
import { executionResultForTaskRun } from "~/models/taskRun.server";
2+
import { executionResultForTaskRun, TaskRunWithAttempts } from "~/models/taskRun.server";
33
import { AuthenticatedEnvironment } from "~/services/apiAuth.server";
4+
import { runStore } from "~/v3/runStore.server";
45
import { BasePresenter } from "./basePresenter.server";
56

67
export class ApiBatchResultsPresenter extends BasePresenter {
@@ -16,16 +17,8 @@ export class ApiBatchResultsPresenter extends BasePresenter {
1617
},
1718
include: {
1819
items: {
19-
include: {
20-
taskRun: {
21-
include: {
22-
attempts: {
23-
orderBy: {
24-
createdAt: "desc",
25-
},
26-
},
27-
},
28-
},
20+
select: {
21+
taskRunId: true,
2922
},
3023
},
3124
},
@@ -35,10 +28,48 @@ export class ApiBatchResultsPresenter extends BasePresenter {
3528
return undefined;
3629
}
3730

31+
const taskRunIds = batchRun.items.map((item) => item.taskRunId);
32+
33+
if (taskRunIds.length === 0) {
34+
return {
35+
id: batchRun.friendlyId,
36+
items: [],
37+
};
38+
}
39+
40+
const taskRuns = await runStore.findRuns(
41+
{
42+
where: { id: { in: taskRunIds } },
43+
select: {
44+
id: true,
45+
friendlyId: true,
46+
status: true,
47+
taskIdentifier: true,
48+
attempts: {
49+
select: {
50+
status: true,
51+
output: true,
52+
outputType: true,
53+
error: true,
54+
},
55+
orderBy: {
56+
createdAt: "desc",
57+
},
58+
},
59+
},
60+
},
61+
this._prisma
62+
);
63+
64+
const runMap = new Map(taskRuns.map((run) => [run.id, run]));
65+
3866
return {
3967
id: batchRun.friendlyId,
4068
items: batchRun.items
41-
.map((item) => executionResultForTaskRun(item.taskRun))
69+
.map((item) => {
70+
const run = runMap.get(item.taskRunId);
71+
return run ? executionResultForTaskRun(run as TaskRunWithAttempts) : undefined;
72+
})
4273
.filter(Boolean),
4374
};
4475
});

apps/webapp/app/v3/services/alerts/deliverAlert.server.ts

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ type DeploymentIntegrationMetadata = {
102102

103103
export class DeliverAlertService extends BaseService {
104104
public async call(alertId: string) {
105-
const alert: FoundAlert | null = await this._prisma.projectAlert.findFirst({
105+
const alertWithoutRun = await this._prisma.projectAlert.findFirst({
106106
where: { id: alertId },
107107
include: {
108108
channel: true,
@@ -112,18 +112,6 @@ export class DeliverAlertService extends BaseService {
112112
},
113113
},
114114
environment: true,
115-
taskRun: {
116-
include: {
117-
lockedBy: true,
118-
lockedToVersion: true,
119-
runtimeEnvironment: {
120-
select: {
121-
type: true,
122-
branchName: true,
123-
},
124-
},
125-
},
126-
},
127115
workerDeployment: {
128116
include: {
129117
worker: {
@@ -142,10 +130,32 @@ export class DeliverAlertService extends BaseService {
142130
},
143131
});
144132

145-
if (!alert) {
133+
if (!alertWithoutRun) {
146134
return;
147135
}
148136

137+
let taskRun: FoundAlert["taskRun"] = null;
138+
if (alertWithoutRun.taskRunId) {
139+
taskRun = await this.runStore.findRun(
140+
{ id: alertWithoutRun.taskRunId },
141+
{
142+
include: {
143+
lockedBy: true,
144+
lockedToVersion: true,
145+
runtimeEnvironment: {
146+
select: {
147+
type: true,
148+
branchName: true,
149+
},
150+
},
151+
},
152+
},
153+
this._prisma
154+
);
155+
}
156+
157+
const alert: FoundAlert = { ...alertWithoutRun, taskRun };
158+
149159
if (alert.status !== "PENDING") {
150160
return;
151161
}

apps/webapp/app/v3/services/cancelTaskAttemptDependencies.server.ts

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ export class CancelTaskAttemptDependenciesService extends BaseService {
1010
where: { id: attemptId },
1111
include: {
1212
dependencies: {
13-
include: {
14-
taskRun: true,
13+
select: {
14+
taskRunId: true,
1515
},
1616
},
1717
batchDependencies: {
1818
include: {
1919
runDependencies: {
20-
include: {
21-
taskRun: true,
20+
select: {
21+
taskRunId: true,
2222
},
2323
},
2424
},
@@ -45,14 +45,53 @@ export class CancelTaskAttemptDependenciesService extends BaseService {
4545
batchDependencies: taskAttempt.batchDependencies,
4646
});
4747

48+
// Hydrate the dependent runs from both relation paths in a single batched read,
49+
// deduping the ids that feed the query while preserving the original iteration order.
50+
const taskRunIds = new Set<string>();
51+
for (const dependency of taskAttempt.dependencies) {
52+
taskRunIds.add(dependency.taskRunId);
53+
}
54+
for (const batchDependency of taskAttempt.batchDependencies) {
55+
for (const runDependency of batchDependency.runDependencies) {
56+
taskRunIds.add(runDependency.taskRunId);
57+
}
58+
}
59+
60+
const runs =
61+
taskRunIds.size > 0
62+
? await this.runStore.findRuns(
63+
{
64+
where: { id: { in: [...taskRunIds] } },
65+
select: {
66+
id: true,
67+
engine: true,
68+
status: true,
69+
friendlyId: true,
70+
taskEventStore: true,
71+
createdAt: true,
72+
completedAt: true,
73+
},
74+
},
75+
this._prisma
76+
)
77+
: [];
78+
79+
const runMap = new Map(runs.map((run) => [run.id, run]));
80+
4881
// TaskAttempt will either have dependencies or batchDependencies
4982
for (const dependency of taskAttempt.dependencies) {
50-
await cancelRunService.call(dependency.taskRun);
83+
const run = runMap.get(dependency.taskRunId);
84+
if (run) {
85+
await cancelRunService.call(run);
86+
}
5187
}
5288

5389
for (const batchDependency of taskAttempt.batchDependencies) {
5490
for (const runDependency of batchDependency.runDependencies) {
55-
await cancelRunService.call(runDependency.taskRun);
91+
const run = runMap.get(runDependency.taskRunId);
92+
if (run) {
93+
await cancelRunService.call(run);
94+
}
5695
}
5796
}
5897
}

0 commit comments

Comments
 (0)