Skip to content

Adding missing task run hierarchy to TaskRun table #1332

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions apps/webapp/app/components/runs/v3/RunInspector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,10 @@ export function RunInspector({
: "–"}
</Property.Value>
</Property.Item>
<Property.Item>
<Property.Label>Run ID</Property.Label>
<Property.Value>{run.id}</Property.Value>
</Property.Item>
</Property.Table>
</div>
) : tab === "context" ? (
Expand Down
42 changes: 21 additions & 21 deletions apps/webapp/app/db.server.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { PrismaClient, Prisma } from "@trigger.dev/database";
import { Prisma, PrismaClient } from "@trigger.dev/database";
import invariant from "tiny-invariant";
import { z } from "zod";
import { logger } from "./services/logger.server";
import { env } from "./env.server";
import { singleton } from "./utils/singleton";
import { logger } from "./services/logger.server";
import { isValidDatabaseUrl } from "./utils/db";
import { singleton } from "./utils/singleton";

export type PrismaTransactionClient = Omit<
PrismaClient,
Expand Down Expand Up @@ -94,6 +94,7 @@ function getClient() {
url: databaseUrl.href,
},
},
// @ts-expect-error
log: [
{
emit: "stdout",
Expand All @@ -107,25 +108,16 @@ function getClient() {
emit: "stdout",
level: "warn",
},
// {
// emit: "stdout",
// level: "query",
// },
// {
// emit: "event",
// level: "query",
// },
],
].concat(
process.env.VERBOSE_PRISMA_LOGS === "1"
? [
{ emit: "event", level: "query" },
{ emit: "stdout", level: "query" },
]
: []
),
});

// client.$on("query", (e) => {
// console.log(`Query tooks ${e.duration}ms`, {
// query: e.query,
// params: e.params,
// duration: e.duration,
// });
// });

// connect eagerly
client.$connect();

Expand Down Expand Up @@ -153,6 +145,7 @@ function getReplicaClient() {
url: replicaUrl.href,
},
},
// @ts-expect-error
log: [
{
emit: "stdout",
Expand All @@ -166,7 +159,14 @@ function getReplicaClient() {
emit: "stdout",
level: "warn",
},
],
].concat(
process.env.VERBOSE_PRISMA_LOGS === "1"
? [
{ emit: "event", level: "query" },
{ emit: "stdout", level: "query" },
]
: []
),
});

// connect eagerly
Expand Down
131 changes: 110 additions & 21 deletions apps/webapp/app/presenters/v3/ApiRetrieveRunPresenter.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
RunStatus,
SerializedError,
TaskRunError,
TriggerFunction,
conditionallyImportPacket,
createJsonErrorObject,
logger,
Expand All @@ -14,6 +15,47 @@ import assertNever from "assert-never";
import { AuthenticatedEnvironment } from "~/services/apiAuth.server";
import { generatePresignedUrl } from "~/v3/r2.server";
import { BasePresenter } from "./basePresenter.server";
import { prisma } from "~/db.server";

// Build 'select' object
const commonRunSelect = {
id: true,
friendlyId: true,
status: true,
taskIdentifier: true,
createdAt: true,
startedAt: true,
updatedAt: true,
completedAt: true,
expiredAt: true,
delayUntil: true,
ttl: true,
tags: true,
costInCents: true,
baseCostInCents: true,
usageDurationMs: true,
idempotencyKey: true,
isTest: true,
depth: true,
lockedToVersion: {
select: {
version: true,
},
},
resumeParentOnCompletion: true,
batch: {
select: {
id: true,
friendlyId: true,
},
},
} satisfies Prisma.TaskRunSelect;

type CommonRelatedRun = Prisma.Result<
typeof prisma.taskRun,
{ select: typeof commonRunSelect },
"findFirstOrThrow"
>;

export class ApiRetrieveRunPresenter extends BasePresenter {
public async call(
Expand All @@ -22,7 +64,7 @@ export class ApiRetrieveRunPresenter extends BasePresenter {
showSecretDetails: boolean
): Promise<RetrieveRunResponse | undefined> {
return this.traceWithEnv("call", env, async (span) => {
const taskRun = await this._prisma.taskRun.findUnique({
const taskRun = await this._replica.taskRun.findFirst({
where: {
friendlyId,
runtimeEnvironmentId: env.id,
Expand All @@ -36,6 +78,23 @@ export class ApiRetrieveRunPresenter extends BasePresenter {
lockedToVersion: true,
schedule: true,
tags: true,
batch: {
select: {
id: true,
friendlyId: true,
},
},
parentTaskRun: {
select: commonRunSelect,
},
rootTaskRun: {
select: commonRunSelect,
},
childRuns: {
select: {
...commonRunSelect,
},
},
},
});

Expand Down Expand Up @@ -101,29 +160,11 @@ export class ApiRetrieveRunPresenter extends BasePresenter {
const apiStatus = ApiRetrieveRunPresenter.apiStatusFromRunStatus(taskRun.status);

return {
id: taskRun.friendlyId,
status: apiStatus,
taskIdentifier: taskRun.taskIdentifier,
idempotencyKey: taskRun.idempotencyKey ?? undefined,
version: taskRun.lockedToVersion ? taskRun.lockedToVersion.version : undefined,
createdAt: taskRun.createdAt ?? undefined,
updatedAt: taskRun.updatedAt ?? undefined,
startedAt: taskRun.startedAt ?? taskRun.lockedAt ?? undefined,
finishedAt: ApiRetrieveRunPresenter.isStatusFinished(apiStatus)
? taskRun.updatedAt
: undefined,
delayedUntil: taskRun.delayUntil ?? undefined,
...createCommonRunStructure(taskRun),
payload: $payload,
payloadPresignedUrl: $payloadPresignedUrl,
output: $output,
outputPresignedUrl: $outputPresignedUrl,
isTest: taskRun.isTest,
ttl: taskRun.ttl ?? undefined,
expiredAt: taskRun.expiredAt ?? undefined,
tags: taskRun.tags.map((t) => t.name).sort((a, b) => a.localeCompare(b)),
costInCents: taskRun.costInCents,
baseCostInCents: taskRun.baseCostInCents,
durationMs: taskRun.usageDurationMs,
schedule: taskRun.schedule
? {
id: taskRun.schedule.friendlyId,
Expand All @@ -138,7 +179,6 @@ export class ApiRetrieveRunPresenter extends BasePresenter {
},
}
: undefined,
...ApiRetrieveRunPresenter.apiBooleanHelpersFromRunStatus(apiStatus),
attempts: !showSecretDetails
? []
: taskRun.attempts.map((a) => ({
Expand All @@ -150,6 +190,13 @@ export class ApiRetrieveRunPresenter extends BasePresenter {
completedAt: a.completedAt ?? undefined,
error: ApiRetrieveRunPresenter.apiErrorFromError(a.error),
})),
relatedRuns: {
root: taskRun.rootTaskRun ? createCommonRunStructure(taskRun.rootTaskRun) : undefined,
parent: taskRun.parentTaskRun
? createCommonRunStructure(taskRun.parentTaskRun)
: undefined,
children: taskRun.childRuns.map((r) => createCommonRunStructure(r)),
},
};
});
}
Expand Down Expand Up @@ -225,6 +272,12 @@ export class ApiRetrieveRunPresenter extends BasePresenter {
}
}

static apiBooleanHelpersFromTaskRunStatus(status: TaskRunStatus) {
return ApiRetrieveRunPresenter.apiBooleanHelpersFromRunStatus(
ApiRetrieveRunPresenter.apiStatusFromRunStatus(status)
);
}

static apiBooleanHelpersFromRunStatus(status: RunStatus) {
const isQueued = status === "QUEUED" || status === "WAITING_FOR_DEPLOY" || status === "DELAYED";
const isExecuting = status === "EXECUTING" || status === "REATTEMPTING" || status === "FROZEN";
Expand Down Expand Up @@ -275,3 +328,39 @@ export class ApiRetrieveRunPresenter extends BasePresenter {
}
}
}

function createCommonRunStructure(run: CommonRelatedRun) {
return {
id: run.friendlyId,
taskIdentifier: run.taskIdentifier,
idempotencyKey: run.idempotencyKey ?? undefined,
version: run.lockedToVersion?.version,
status: ApiRetrieveRunPresenter.apiStatusFromRunStatus(run.status),
createdAt: run.createdAt,
startedAt: run.startedAt ?? undefined,
updatedAt: run.updatedAt,
finishedAt: run.completedAt ?? undefined,
expiredAt: run.expiredAt ?? undefined,
delayedUntil: run.delayUntil ?? undefined,
ttl: run.ttl ?? undefined,
costInCents: run.costInCents,
baseCostInCents: run.baseCostInCents,
durationMs: run.usageDurationMs,
isTest: run.isTest,
depth: run.depth,
tags: run.tags
.map((t: { name: string }) => t.name)
.sort((a: string, b: string) => a.localeCompare(b)),
...ApiRetrieveRunPresenter.apiBooleanHelpersFromTaskRunStatus(run.status),
triggerFunction: resolveTriggerFunction(run),
batchId: run.batch?.friendlyId,
};
}

function resolveTriggerFunction(run: CommonRelatedRun): TriggerFunction {
if (run.batch) {
return run.resumeParentOnCompletion ? "batchTriggerAndWait" : "batchTrigger";
} else {
return run.resumeParentOnCompletion ? "triggerAndWait" : "trigger";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ export class ApiRunListPresenter extends BasePresenter {
costInCents: run.costInCents,
baseCostInCents: run.baseCostInCents,
durationMs: run.usageDurationMs,
depth: run.depth,
...ApiRetrieveRunPresenter.apiBooleanHelpersFromRunStatus(
ApiRetrieveRunPresenter.apiStatusFromRunStatus(run.status)
),
Expand Down
3 changes: 3 additions & 0 deletions apps/webapp/app/presenters/v3/RunListPresenter.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ export class RunListPresenter extends BasePresenter {
baseCostInCents: number;
usageDurationMs: BigInt;
tags: string[];
depth: number;
}[]
>`
SELECT
Expand All @@ -190,6 +191,7 @@ export class RunListPresenter extends BasePresenter {
tr."baseCostInCents" AS "baseCostInCents",
tr."costInCents" AS "costInCents",
tr."usageDurationMs" AS "usageDurationMs",
tr."depth" AS "depth",
array_remove(array_agg(tag.name), NULL) AS "tags"
FROM
${sqlDatabaseSchema}."TaskRun" tr
Expand Down Expand Up @@ -333,6 +335,7 @@ WHERE
baseCostInCents: run.baseCostInCents,
usageDurationMs: Number(run.usageDurationMs),
tags: run.tags.sort((a, b) => a.localeCompare(b)),
depth: run.depth,
};
}),
pagination: {
Expand Down
1 change: 1 addition & 0 deletions apps/webapp/app/presenters/v3/SpanPresenter.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ export class SpanPresenter extends BasePresenter {
};

return {
id: run.id,
friendlyId: run.friendlyId,
status: run.status,
createdAt: run.createdAt,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,14 @@ function RunBody({
: "–"}
</Property.Value>
</Property.Item>
<Property.Item>
<Property.Label>Run ID</Property.Label>
<Property.Value>{run.friendlyId}</Property.Value>
</Property.Item>
<Property.Item>
<Property.Label>Internal ID</Property.Label>
<Property.Value>{run.id}</Property.Value>
</Property.Item>
</Property.Table>
</div>
) : tab === "context" ? (
Expand Down
1 change: 1 addition & 0 deletions apps/webapp/app/v3/services/batchTriggerTask.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ export class BatchTriggerTaskService extends BaseService {
options: {
...item.options,
dependentBatch: dependentAttempt?.id ? batch.friendlyId : undefined, // Only set dependentBatch if dependentAttempt is set which means batchTriggerAndWait was called
parentBatch: dependentAttempt?.id ? undefined : batch.friendlyId, // Only set parentBatch if dependentAttempt is NOT set which means batchTrigger was called
},
},
{
Expand Down
Loading
Loading