chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,296 @@
|
||||
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",
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user