Files
triggerdotdev--trigger.dev/apps/webapp/app/v3/services/alerts/performTaskRunAlerts.server.ts
T
2026-07-13 13:32:57 +08:00

98 lines
2.9 KiB
TypeScript

import { type RunStore } from "@internal/run-store";
import { type Prisma, type ProjectAlertChannel } from "@trigger.dev/database";
import { type PrismaClientOrTransaction, type prisma } from "~/db.server";
import { alertsWorker } from "~/v3/alertsWorker.server";
import type { ControlPlaneResolver } from "~/v3/runOpsMigration/controlPlaneResolver.server";
import { controlPlaneResolver as defaultControlPlaneResolver } from "~/v3/runOpsMigration/controlPlaneResolver.server";
import { BaseService } from "../baseService.server";
import { DeliverAlertService } from "./deliverAlert.server";
// The alert hydration reads only run-ops scalars (id/projectId/runtimeEnvironmentId); the env's
// type (and its parent's) is resolved via the control-plane resolver so the run-ops DB can split
// without a cross-provider join. The prior `lockedBy` + `runtimeEnvironment` includes were unused.
type FoundRun = Prisma.Result<
typeof prisma.taskRun,
{ select: { id: true; projectId: true; runtimeEnvironmentId: true } },
"findUniqueOrThrow"
>;
export class PerformTaskRunAlertsService extends BaseService {
#controlPlaneResolver: ControlPlaneResolver;
constructor(
opts: {
prisma?: PrismaClientOrTransaction;
replica?: PrismaClientOrTransaction;
runStore?: RunStore;
controlPlaneResolver?: ControlPlaneResolver;
} = {}
) {
super(opts.prisma, opts.replica, opts.runStore);
this.#controlPlaneResolver = opts.controlPlaneResolver ?? defaultControlPlaneResolver;
}
public async call(runId: string) {
const run = await this.runStore.findRun(
{ id: runId },
{
select: {
id: true,
projectId: true,
runtimeEnvironmentId: true,
},
},
this._prisma
);
if (!run) {
return;
}
const env = await this.#controlPlaneResolver.resolveEnv(run.runtimeEnvironmentId);
if (!env) {
return;
}
const alertChannels = await this._prisma.projectAlertChannel.findMany({
where: {
projectId: run.projectId,
alertTypes: {
has: "TASK_RUN",
},
environmentTypes: {
has: env.parentEnvironmentType ?? env.type,
},
enabled: true,
},
});
for (const alertChannel of alertChannels) {
await this.#createAndSendAlert(alertChannel, run);
}
}
async #createAndSendAlert(alertChannel: ProjectAlertChannel, run: FoundRun) {
await DeliverAlertService.createAndSendAlert(
{
channelId: alertChannel.id,
channelType: alertChannel.type,
projectId: run.projectId,
environmentId: run.runtimeEnvironmentId,
alertType: "TASK_RUN",
taskRunId: run.id,
},
this._prisma
);
}
static async enqueue(runId: string, runAt?: Date) {
return await alertsWorker.enqueue({
id: `performTaskRunAlerts:${runId}`,
job: "v3.performTaskRunAlerts",
payload: { runId },
availableAt: runAt,
});
}
}