// A standalone wait token is minted with a cuid id and, having no owning run, is written to the // control-plane store. Under the split topology the run-ops read replica is a distinct database // that does not hold it, so the public token routes must fan out to the control-plane replica or // the token is reported missing. These reads run as real queries against two containers. import { heteroPostgresTest } from "@internal/testcontainers"; import { WaitpointId } from "@trigger.dev/core/v3/isomorphic"; import { describe, expect, vi } from "vitest"; import type { PrismaClient } from "@trigger.dev/database"; import type { PrismaReplicaClient } from "~/db.server"; import { resolveWaitpointThroughReadThrough } from "~/runEngine/concerns/resolveWaitpointThroughReadThrough.server"; import { readThroughRun } from "./readThrough.server"; vi.setConfig({ testTimeout: 60_000 }); async function seedControlPlaneEnv(prisma: PrismaClient, suffix: string) { const organization = await prisma.organization.create({ data: { title: `Org ${suffix}`, slug: `org-${suffix}` }, }); const project = await prisma.project.create({ data: { name: `Project ${suffix}`, slug: `project-${suffix}`, externalRef: `proj_${suffix}`, organizationId: organization.id, }, }); const environment = await prisma.runtimeEnvironment.create({ data: { type: "PRODUCTION", slug: `prod-${suffix}`, projectId: project.id, organizationId: organization.id, apiKey: `tr_prod_${suffix}`, pkApiKey: `pk_prod_${suffix}`, shortcode: `short_${suffix}`, maximumConcurrencyLimit: 10, }, }); return { organization, project, environment }; } async function seedStandaloneToken(prisma: PrismaClient, environmentId: string, projectId: string) { const { id, friendlyId } = WaitpointId.generate(); await prisma.waitpoint.create({ data: { id, friendlyId, type: "MANUAL", status: "PENDING", idempotencyKey: id, userProvidedIdempotencyKey: false, environmentId, projectId, }, }); return { id, friendlyId }; } describe("public wait-token resolution across the split boundary", () => { heteroPostgresTest( "a control-plane-resident standalone token is found when the run-ops replica does not hold it", async ({ prisma14, prisma17 }) => { const { project, environment } = await seedControlPlaneEnv(prisma14, "token_cp"); const { id: waitpointId } = await seedStandaloneToken(prisma14, environment.id, project.id); const waitpoint = await resolveWaitpointThroughReadThrough({ waitpointId, environmentId: environment.id, read: (client: PrismaReplicaClient) => client.waitpoint.findFirst({ where: { id: waitpointId, environmentId: environment.id }, }), deps: { // Pin split-on explicitly: without it the fan-out gate falls back to the // ambient RUN_OPS_SPLIT_ENABLED env, which is unset in CI (single-DB // passthrough reads only the run-ops replica and never fans out to the // control-plane legacy replica that holds this cuid-shaped token). splitEnabled: true, newClient: prisma17 as unknown as PrismaReplicaClient, legacyReplica: prisma14 as unknown as PrismaReplicaClient, }, }); expect(waitpoint).not.toBeNull(); expect(waitpoint?.id).toBe(waitpointId); } ); heteroPostgresTest( "pinning both reads at the run-ops replica misses the control-plane token", async ({ prisma14, prisma17 }) => { const { project, environment } = await seedControlPlaneEnv(prisma14, "token_miss"); const { id: waitpointId } = await seedStandaloneToken(prisma14, environment.id, project.id); const waitpoint = await resolveWaitpointThroughReadThrough({ waitpointId, environmentId: environment.id, read: (client: PrismaReplicaClient) => client.waitpoint.findFirst({ where: { id: waitpointId, environmentId: environment.id }, }), deps: { newClient: prisma17 as unknown as PrismaReplicaClient, legacyReplica: prisma17 as unknown as PrismaReplicaClient, // The run-ops-primary fallback is also pinned at run-ops, which does not hold this // control-plane token, so the miss stays a miss (fallback never reads the control-plane). newPrimary: prisma17 as unknown as PrismaReplicaClient, }, }); expect(waitpoint).toBeNull(); } ); heteroPostgresTest( "the read gate forces fan-out so a control-plane token resolves while the mint flag is off", async ({ prisma14, prisma17 }) => { const { project, environment } = await seedControlPlaneEnv(prisma14, "token_gate"); const { id: waitpointId } = await seedStandaloneToken(prisma14, environment.id, project.id); const read = (client: PrismaReplicaClient) => client.waitpoint.findFirst({ where: { id: waitpointId, environmentId: environment.id }, }); const gated = await resolveWaitpointThroughReadThrough({ waitpointId, environmentId: environment.id, read, deps: { splitEnabled: true, newClient: prisma17 as unknown as PrismaReplicaClient, legacyReplica: prisma14 as unknown as PrismaReplicaClient, }, }); expect(gated).not.toBeNull(); expect(gated?.id).toBe(waitpointId); const passthrough = await readThroughRun({ runId: waitpointId, environmentId: environment.id, readNew: (c) => read(c), readLegacy: (r) => read(r), deps: { splitEnabled: false, newClient: prisma17 as unknown as PrismaReplicaClient, legacyReplica: prisma14 as unknown as PrismaReplicaClient, }, }); expect(gated).not.toBeNull(); expect(passthrough.source).toBe("not-found"); } ); });