111 lines
3.4 KiB
TypeScript
111 lines
3.4 KiB
TypeScript
import { type LoaderFunctionArgs } from "@remix-run/server-runtime";
|
|
import { type TaskRunStatus } from "@trigger.dev/database";
|
|
import { z } from "zod";
|
|
import { $replica } from "~/db.server";
|
|
import { clickhouseFactory } from "~/services/clickhouse/clickhouseFactoryInstance.server";
|
|
import { loadProjectEnvironmentFromRequest } from "~/services/loadProjectEnvironmentFromRequest.server";
|
|
import { RunsRepository } from "~/services/runsRepository/runsRepository.server";
|
|
import { runIdsQueryParam } from "~/utils/searchParams";
|
|
|
|
const SearchParamsSchema = z.object({
|
|
runIds: runIdsQueryParam,
|
|
});
|
|
|
|
const ROOT_CREATED_AT_SAFETY_MARGIN_MS = 5 * 60 * 1000;
|
|
|
|
type RootRun = { id: string; friendlyId: string; createdAt: Date };
|
|
type ChildStatusEntry = { status: TaskRunStatus; count: number };
|
|
type GroupedChildStatus = {
|
|
rootRunId: string;
|
|
status: TaskRunStatus;
|
|
count: number;
|
|
};
|
|
|
|
function mapGroupedStatusesToFriendlyIds(
|
|
grouped: GroupedChildStatus[],
|
|
roots: RootRun[]
|
|
): Map<string, ChildStatusEntry[]> {
|
|
const rootFriendlyIdById = new Map(roots.map((run) => [run.id, run.friendlyId]));
|
|
const statusesByFriendlyId = new Map<string, ChildStatusEntry[]>();
|
|
|
|
for (const item of grouped) {
|
|
const friendlyId = rootFriendlyIdById.get(item.rootRunId);
|
|
if (!friendlyId) continue;
|
|
|
|
const existing = statusesByFriendlyId.get(friendlyId) ?? [];
|
|
existing.push({
|
|
status: item.status,
|
|
count: item.count,
|
|
});
|
|
statusesByFriendlyId.set(friendlyId, existing);
|
|
}
|
|
|
|
return statusesByFriendlyId;
|
|
}
|
|
|
|
function childrenStatusesResponseForRunIds(
|
|
runIds: string[],
|
|
statusesByFriendlyId: Map<string, ChildStatusEntry[]>
|
|
) {
|
|
return {
|
|
runs: runIds.map((friendlyId) => ({
|
|
friendlyId,
|
|
statuses: (statusesByFriendlyId.get(friendlyId) ?? []).filter((entry) => entry.count > 0),
|
|
})),
|
|
};
|
|
}
|
|
|
|
export async function loader({ request, params }: LoaderFunctionArgs) {
|
|
const url = new URL(request.url);
|
|
const { runIds } = SearchParamsSchema.parse(Object.fromEntries(url.searchParams));
|
|
|
|
if (runIds.length === 0) {
|
|
return { runs: [] };
|
|
}
|
|
|
|
const { project, environment } = await loadProjectEnvironmentFromRequest(request, params);
|
|
|
|
const clickhouse = await clickhouseFactory.getClickhouseForOrganization(
|
|
project.organizationId,
|
|
"standard"
|
|
);
|
|
const runsRepository = new RunsRepository({ clickhouse, prisma: $replica });
|
|
|
|
const { runs: roots } = await runsRepository.listRuns({
|
|
organizationId: project.organizationId,
|
|
projectId: project.id,
|
|
environmentId: environment.id,
|
|
runId: runIds,
|
|
page: { size: 100 },
|
|
});
|
|
|
|
if (roots.length === 0) {
|
|
return { runs: [] };
|
|
}
|
|
|
|
const earliestRootCreatedAtMs = Math.min(...roots.map((run) => run.createdAt.getTime()));
|
|
const sinceMs = Math.max(0, earliestRootCreatedAtMs - ROOT_CREATED_AT_SAFETY_MARGIN_MS);
|
|
|
|
const [queryError, groupedRows] = await clickhouse.taskRuns.getChildRunStatusCounts({
|
|
organizationId: project.organizationId,
|
|
projectId: project.id,
|
|
environmentId: environment.id,
|
|
rootRunIds: roots.map((run) => run.id),
|
|
since: sinceMs,
|
|
});
|
|
|
|
if (queryError) {
|
|
throw queryError;
|
|
}
|
|
|
|
const grouped: GroupedChildStatus[] = groupedRows.map((row) => ({
|
|
rootRunId: row.root_run_id,
|
|
status: row.status as TaskRunStatus,
|
|
count: row.count,
|
|
}));
|
|
|
|
const statusesByFriendlyId = mapGroupedStatusesToFriendlyIds(grouped, roots);
|
|
|
|
return childrenStatusesResponseForRunIds(runIds, statusesByFriendlyId);
|
|
}
|