297 lines
7.4 KiB
TypeScript
297 lines
7.4 KiB
TypeScript
import type { Prisma } from "@trigger.dev/database";
|
|
import { logger } from "~/services/logger.server";
|
|
import { isFinalAttemptStatus, isFinalRunStatus } from "../taskStatus";
|
|
import { BaseService } from "./baseService.server";
|
|
import { ResumeBatchRunService } from "./resumeBatchRun.server";
|
|
import { ResumeTaskDependencyService } from "./resumeTaskDependency.server";
|
|
import { $transaction } from "~/db.server";
|
|
import { completeBatchTaskRunItemV3 } from "./batchTriggerV3.server";
|
|
|
|
type Output =
|
|
| {
|
|
success: true;
|
|
action:
|
|
| "resume-scheduled"
|
|
| "batch-resume-scheduled"
|
|
| "no-dependencies"
|
|
| "not-finished"
|
|
| "dev";
|
|
}
|
|
| {
|
|
success: false;
|
|
error: string;
|
|
};
|
|
|
|
const taskRunDependencySelect = {
|
|
select: {
|
|
id: true,
|
|
taskRunId: true,
|
|
taskRun: {
|
|
select: {
|
|
id: true,
|
|
status: true,
|
|
friendlyId: true,
|
|
runtimeEnvironment: {
|
|
select: {
|
|
type: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
dependentAttempt: {
|
|
select: {
|
|
id: true,
|
|
},
|
|
},
|
|
dependentBatchRun: {
|
|
select: {
|
|
id: true,
|
|
batchVersion: true,
|
|
},
|
|
},
|
|
},
|
|
} as const;
|
|
|
|
type Dependency = Prisma.TaskRunDependencyGetPayload<typeof taskRunDependencySelect>;
|
|
|
|
/** This will resume a dependent (parent) run if there is one and it makes sense. */
|
|
export class ResumeDependentParentsService extends BaseService {
|
|
public async call({ id }: { id: string }): Promise<Output> {
|
|
try {
|
|
const dependency = await this._prisma.taskRunDependency.findFirst({
|
|
...taskRunDependencySelect,
|
|
where: {
|
|
taskRunId: id,
|
|
},
|
|
});
|
|
|
|
logger.log("ResumeDependentParentsService: tried to find dependency", {
|
|
runId: id,
|
|
dependency: dependency,
|
|
});
|
|
|
|
if (!dependency) {
|
|
logger.log("ResumeDependentParentsService: dependency not found", {
|
|
runId: id,
|
|
});
|
|
|
|
//no dependency, that's fine most runs won't have one.
|
|
return {
|
|
success: true,
|
|
action: "no-dependencies",
|
|
};
|
|
}
|
|
|
|
if (dependency.taskRun.runtimeEnvironment.type === "DEVELOPMENT") {
|
|
return {
|
|
success: true,
|
|
action: "dev",
|
|
};
|
|
}
|
|
|
|
if (!isFinalRunStatus(dependency.taskRun.status)) {
|
|
logger.debug(
|
|
"ResumeDependentParentsService: run not finished yet, can't resume parent yet",
|
|
{
|
|
runId: id,
|
|
dependency,
|
|
}
|
|
);
|
|
|
|
// the child run isn't finished yet, so we can't resume the parent yet.
|
|
return {
|
|
success: true,
|
|
action: "not-finished",
|
|
};
|
|
}
|
|
|
|
if (dependency.dependentAttempt) {
|
|
return this.#singleRunDependency(dependency);
|
|
} else if (dependency.dependentBatchRun) {
|
|
return this.#batchRunDependency(dependency);
|
|
} else {
|
|
logger.error("ResumeDependentParentsService: dependency has no dependencies", {
|
|
runId: id,
|
|
dependency,
|
|
});
|
|
|
|
return {
|
|
success: false,
|
|
error: `Dependency has no dependencies (single or batch)`,
|
|
};
|
|
}
|
|
} catch (error) {
|
|
return {
|
|
success: false,
|
|
error: error instanceof Error ? error.message : JSON.stringify(error),
|
|
};
|
|
}
|
|
}
|
|
|
|
async #singleRunDependency(dependency: Dependency): Promise<Output> {
|
|
logger.debug(
|
|
`ResumeDependentParentsService.singleRunDependency(): Resuming dependent parent for run`,
|
|
{
|
|
dependency,
|
|
}
|
|
);
|
|
|
|
const lastAttempt = await this._prisma.taskRunAttempt.findFirst({
|
|
select: {
|
|
id: true,
|
|
status: true,
|
|
},
|
|
where: {
|
|
taskRunId: dependency.taskRunId,
|
|
},
|
|
orderBy: {
|
|
id: "desc",
|
|
},
|
|
});
|
|
|
|
if (!lastAttempt) {
|
|
logger.error(
|
|
"ResumeDependentParentsService.singleRunDependency(): dependency child attempt not found",
|
|
{
|
|
dependency,
|
|
}
|
|
);
|
|
|
|
return {
|
|
success: false,
|
|
error: `Dependency child attempt not found for run ${dependency.taskRunId}`,
|
|
};
|
|
}
|
|
|
|
if (!isFinalAttemptStatus(lastAttempt.status)) {
|
|
//We still want to continue if this happens because the run is final but log it
|
|
logger.error(
|
|
"ResumeDependentParentsService.singleRunDependency(): dependency child attempt not final, but the run is.",
|
|
{
|
|
dependency,
|
|
lastAttempt,
|
|
}
|
|
);
|
|
|
|
return {
|
|
success: false,
|
|
error: `Dependency child attempt not final, but the run is`,
|
|
};
|
|
}
|
|
|
|
//resume the dependent task
|
|
await ResumeTaskDependencyService.enqueue(dependency.id, lastAttempt.id);
|
|
return {
|
|
success: true,
|
|
action: "resume-scheduled",
|
|
};
|
|
}
|
|
|
|
async #batchRunDependency(dependency: Dependency): Promise<Output> {
|
|
logger.debug(
|
|
`ResumeDependentParentsService.batchRunDependency(): Resuming dependent batch for run`,
|
|
{
|
|
dependency,
|
|
}
|
|
);
|
|
|
|
if (!dependency.dependentBatchRun) {
|
|
logger.error(
|
|
"ResumeDependentParentsService.batchRunDependency(): dependency has no dependent batch",
|
|
{
|
|
dependency,
|
|
}
|
|
);
|
|
|
|
return {
|
|
success: false,
|
|
error: `Dependency has no dependent batch`,
|
|
};
|
|
}
|
|
|
|
const lastAttempt = await this._prisma.taskRunAttempt.findFirst({
|
|
select: {
|
|
id: true,
|
|
status: true,
|
|
},
|
|
where: {
|
|
taskRunId: dependency.taskRunId,
|
|
},
|
|
orderBy: {
|
|
id: "desc",
|
|
},
|
|
});
|
|
|
|
if (!lastAttempt) {
|
|
logger.error(
|
|
"ResumeDependentParentsService.singleRunDependency(): dependency child attempt not found",
|
|
{
|
|
dependency,
|
|
}
|
|
);
|
|
|
|
return {
|
|
success: false,
|
|
error: `Dependency child attempt not found for run ${dependency.taskRunId}`,
|
|
};
|
|
}
|
|
|
|
logger.log(
|
|
"ResumeDependentParentsService.batchRunDependency(): Setting the batchTaskRunItem to COMPLETED",
|
|
{
|
|
dependency,
|
|
lastAttempt,
|
|
}
|
|
);
|
|
|
|
if (dependency.dependentBatchRun!.batchVersion === "v3") {
|
|
const batchTaskRunItem = await this._prisma.batchTaskRunItem.findFirst({
|
|
where: {
|
|
batchTaskRunId: dependency.dependentBatchRun!.id,
|
|
taskRunId: dependency.taskRunId,
|
|
},
|
|
});
|
|
|
|
if (batchTaskRunItem) {
|
|
await completeBatchTaskRunItemV3(
|
|
batchTaskRunItem.id,
|
|
batchTaskRunItem.batchTaskRunId,
|
|
this._prisma,
|
|
true,
|
|
lastAttempt.id
|
|
);
|
|
} else {
|
|
logger.debug(
|
|
"ResumeDependentParentsService.batchRunDependency() v3: batchTaskRunItem not found",
|
|
{
|
|
dependency,
|
|
lastAttempt,
|
|
}
|
|
);
|
|
}
|
|
} else {
|
|
await $transaction(this._prisma, async (tx) => {
|
|
await tx.batchTaskRunItem.update({
|
|
where: {
|
|
batchTaskRunId_taskRunId: {
|
|
batchTaskRunId: dependency.dependentBatchRun!.id,
|
|
taskRunId: dependency.taskRunId,
|
|
},
|
|
},
|
|
data: {
|
|
status: "COMPLETED",
|
|
taskRunAttemptId: lastAttempt.id,
|
|
},
|
|
});
|
|
|
|
await ResumeBatchRunService.enqueue(dependency.dependentBatchRun!.id, false, tx);
|
|
});
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
action: "batch-resume-scheduled",
|
|
};
|
|
}
|
|
}
|