chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:32:57 +08:00
commit cd420f9332
4811 changed files with 884702 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
../../.env
@@ -0,0 +1,6 @@
node_modules
dist
generated/run-ops
# Ensure the .env symlink is not removed by accident
!.env
@@ -0,0 +1,41 @@
{
"name": "@internal/run-ops-database",
"private": true,
"version": "0.0.1",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"@triggerdotdev/source": "./src/index.ts",
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"default": "./dist/index.js"
},
"./prisma/schema.prisma": "./prisma/schema.prisma",
"./prisma/*": "./prisma/*",
"./package.json": "./package.json"
},
"dependencies": {
"@prisma/client": "6.14.0",
"prisma": "6.14.0"
},
"devDependencies": {
"rimraf": "6.0.1",
"vitest": "4.1.7"
},
"scripts": {
"clean": "rimraf dist",
"generate": "node ../../scripts/retry-prisma-generate.mjs",
"db:migrate:dev:create": "pnpm run format:prisma && prisma migrate dev --create-only",
"format:prisma": "prisma format",
"db:migrate:deploy": "node scripts/migrate.mjs deploy",
"db:migrate:status": "node scripts/migrate.mjs status",
"db:push": "prisma db push",
"test": "vitest run",
"typecheck": "tsc --noEmit",
"build": "pnpm run clean && tsc --noEmit false --outDir dist --declaration",
"dev": "tsc --noEmit false --outDir dist --declaration --watch",
"db:studio": "prisma studio",
"db:reset": "prisma migrate reset"
}
}
@@ -0,0 +1,621 @@
-- CreateEnum
CREATE TYPE "public"."RuntimeEnvironmentType" AS ENUM ('PRODUCTION', 'STAGING', 'DEVELOPMENT', 'PREVIEW');
-- CreateEnum
CREATE TYPE "public"."TaskRunStatus" AS ENUM ('DELAYED', 'PENDING', 'PENDING_VERSION', 'WAITING_FOR_DEPLOY', 'DEQUEUED', 'EXECUTING', 'WAITING_TO_RESUME', 'RETRYING_AFTER_FAILURE', 'PAUSED', 'CANCELED', 'INTERRUPTED', 'COMPLETED_SUCCESSFULLY', 'COMPLETED_WITH_ERRORS', 'SYSTEM_FAILURE', 'CRASHED', 'EXPIRED', 'TIMED_OUT');
-- CreateEnum
CREATE TYPE "public"."RunEngineVersion" AS ENUM ('V1', 'V2');
-- CreateEnum
CREATE TYPE "public"."TaskRunExecutionStatus" AS ENUM ('RUN_CREATED', 'DELAYED', 'QUEUED', 'QUEUED_EXECUTING', 'PENDING_EXECUTING', 'EXECUTING', 'EXECUTING_WITH_WAITPOINTS', 'SUSPENDED', 'PENDING_CANCEL', 'FINISHED');
-- CreateEnum
CREATE TYPE "public"."TaskRunCheckpointType" AS ENUM ('DOCKER', 'KUBERNETES', 'COMPUTE');
-- CreateEnum
CREATE TYPE "public"."WaitpointType" AS ENUM ('RUN', 'DATETIME', 'MANUAL', 'BATCH');
-- CreateEnum
CREATE TYPE "public"."WaitpointStatus" AS ENUM ('PENDING', 'COMPLETED');
-- CreateEnum
CREATE TYPE "public"."TaskRunAttemptStatus" AS ENUM ('PENDING', 'EXECUTING', 'PAUSED', 'FAILED', 'CANCELED', 'COMPLETED');
-- CreateEnum
CREATE TYPE "public"."BatchTaskRunStatus" AS ENUM ('PENDING', 'PROCESSING', 'COMPLETED', 'PARTIAL_FAILED', 'ABORTED');
-- CreateEnum
CREATE TYPE "public"."BatchTaskRunItemStatus" AS ENUM ('PENDING', 'FAILED', 'CANCELED', 'COMPLETED');
-- CreateEnum
CREATE TYPE "public"."CheckpointType" AS ENUM ('DOCKER', 'KUBERNETES');
-- CreateEnum
CREATE TYPE "public"."CheckpointRestoreEventType" AS ENUM ('CHECKPOINT', 'RESTORE');
-- CreateTable
CREATE TABLE "public"."TaskRun" (
"id" TEXT NOT NULL,
"number" INTEGER NOT NULL DEFAULT 0,
"friendlyId" TEXT NOT NULL,
"engine" "public"."RunEngineVersion" NOT NULL DEFAULT 'V1',
"status" "public"."TaskRunStatus" NOT NULL DEFAULT 'PENDING',
"statusReason" TEXT,
"idempotencyKey" TEXT,
"idempotencyKeyExpiresAt" TIMESTAMP(3),
"idempotencyKeyOptions" JSONB,
"debounce" JSONB,
"taskIdentifier" TEXT NOT NULL,
"isTest" BOOLEAN NOT NULL DEFAULT false,
"payload" TEXT NOT NULL,
"payloadType" TEXT NOT NULL DEFAULT 'application/json',
"context" JSONB,
"traceContext" JSONB,
"traceId" TEXT NOT NULL,
"spanId" TEXT NOT NULL,
"runtimeEnvironmentId" TEXT NOT NULL,
"environmentType" "public"."RuntimeEnvironmentType",
"projectId" TEXT NOT NULL,
"organizationId" TEXT,
"queue" TEXT NOT NULL,
"lockedQueueId" TEXT,
"masterQueue" TEXT NOT NULL DEFAULT 'main',
"region" TEXT,
"secondaryMasterQueue" TEXT,
"attemptNumber" INTEGER,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"runTags" TEXT[],
"taskVersion" TEXT,
"sdkVersion" TEXT,
"cliVersion" TEXT,
"startedAt" TIMESTAMP(3),
"executedAt" TIMESTAMP(3),
"completedAt" TIMESTAMP(3),
"machinePreset" TEXT,
"usageDurationMs" INTEGER NOT NULL DEFAULT 0,
"costInCents" DOUBLE PRECISION NOT NULL DEFAULT 0,
"baseCostInCents" DOUBLE PRECISION NOT NULL DEFAULT 0,
"lockedAt" TIMESTAMP(3),
"lockedById" TEXT,
"lockedToVersionId" TEXT,
"priorityMs" INTEGER NOT NULL DEFAULT 0,
"concurrencyKey" TEXT,
"delayUntil" TIMESTAMP(3),
"queuedAt" TIMESTAMP(3),
"ttl" TEXT,
"expiredAt" TIMESTAMP(3),
"maxAttempts" INTEGER,
"lockedRetryConfig" JSONB,
"oneTimeUseToken" TEXT,
"taskEventStore" TEXT NOT NULL DEFAULT 'taskEvent',
"queueTimestamp" TIMESTAMP(3),
"scheduleInstanceId" TEXT,
"scheduleId" TEXT,
"bulkActionGroupIds" TEXT[] DEFAULT ARRAY[]::TEXT[],
"logsDeletedAt" TIMESTAMP(3),
"replayedFromTaskRunFriendlyId" TEXT,
"rootTaskRunId" TEXT,
"parentTaskRunId" TEXT,
"parentTaskRunAttemptId" TEXT,
"batchId" TEXT,
"resumeParentOnCompletion" BOOLEAN NOT NULL DEFAULT false,
"depth" INTEGER NOT NULL DEFAULT 0,
"parentSpanId" TEXT,
"runChainState" JSONB,
"seedMetadata" TEXT,
"seedMetadataType" TEXT NOT NULL DEFAULT 'application/json',
"metadata" TEXT,
"metadataType" TEXT NOT NULL DEFAULT 'application/json',
"metadataVersion" INTEGER NOT NULL DEFAULT 1,
"annotations" JSONB,
"isWarmStart" BOOLEAN,
"output" TEXT,
"outputType" TEXT NOT NULL DEFAULT 'application/json',
"error" JSONB,
"planType" TEXT,
"maxDurationInSeconds" INTEGER,
"realtimeStreamsVersion" TEXT NOT NULL DEFAULT 'v1',
"realtimeStreams" TEXT[] DEFAULT ARRAY[]::TEXT[],
"streamBasinName" TEXT,
CONSTRAINT "TaskRun_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "public"."TaskRunExecutionSnapshot" (
"id" TEXT NOT NULL,
"engine" "public"."RunEngineVersion" NOT NULL DEFAULT 'V2',
"executionStatus" "public"."TaskRunExecutionStatus" NOT NULL,
"description" TEXT NOT NULL,
"isValid" BOOLEAN NOT NULL DEFAULT true,
"error" TEXT,
"previousSnapshotId" TEXT,
"runId" TEXT NOT NULL,
"runStatus" "public"."TaskRunStatus" NOT NULL,
"batchId" TEXT,
"attemptNumber" INTEGER,
"environmentId" TEXT NOT NULL,
"environmentType" "public"."RuntimeEnvironmentType" NOT NULL,
"projectId" TEXT NOT NULL,
"organizationId" TEXT NOT NULL,
"completedWaitpointOrder" TEXT[],
"checkpointId" TEXT,
"workerId" TEXT,
"runnerId" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"lastHeartbeatAt" TIMESTAMP(3),
"metadata" JSONB,
CONSTRAINT "TaskRunExecutionSnapshot_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "public"."TaskRunCheckpoint" (
"id" TEXT NOT NULL,
"friendlyId" TEXT NOT NULL,
"type" "public"."TaskRunCheckpointType" NOT NULL,
"location" TEXT NOT NULL,
"imageRef" TEXT,
"reason" TEXT,
"metadata" TEXT,
"projectId" TEXT NOT NULL,
"runtimeEnvironmentId" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "TaskRunCheckpoint_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "public"."Waitpoint" (
"id" TEXT NOT NULL,
"friendlyId" TEXT NOT NULL,
"type" "public"."WaitpointType" NOT NULL,
"status" "public"."WaitpointStatus" NOT NULL DEFAULT 'PENDING',
"completedAt" TIMESTAMP(3),
"idempotencyKey" TEXT NOT NULL,
"userProvidedIdempotencyKey" BOOLEAN NOT NULL,
"idempotencyKeyExpiresAt" TIMESTAMP(3),
"inactiveIdempotencyKey" TEXT,
"completedByTaskRunId" TEXT,
"completedAfter" TIMESTAMP(3),
"completedByBatchId" TEXT,
"output" TEXT,
"outputType" TEXT NOT NULL DEFAULT 'application/json',
"outputIsError" BOOLEAN NOT NULL DEFAULT false,
"projectId" TEXT NOT NULL,
"environmentId" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"tags" TEXT[],
CONSTRAINT "Waitpoint_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "public"."TaskRunWaitpoint" (
"id" TEXT NOT NULL,
"taskRunId" TEXT NOT NULL,
"waitpointId" TEXT NOT NULL,
"projectId" TEXT NOT NULL,
"spanIdToComplete" TEXT,
"batchId" TEXT,
"batchIndex" INTEGER,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "TaskRunWaitpoint_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "public"."WaitpointRunConnection" (
"id" TEXT NOT NULL,
"taskRunId" TEXT NOT NULL,
"waitpointId" TEXT NOT NULL,
CONSTRAINT "WaitpointRunConnection_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "public"."CompletedWaitpoint" (
"id" TEXT NOT NULL,
"snapshotId" TEXT NOT NULL,
"waitpointId" TEXT NOT NULL,
CONSTRAINT "CompletedWaitpoint_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "public"."WaitpointTag" (
"id" TEXT NOT NULL,
"name" TEXT NOT NULL,
"environmentId" TEXT NOT NULL,
"projectId" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "WaitpointTag_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "public"."TaskRunTag" (
"id" TEXT NOT NULL,
"name" TEXT NOT NULL,
"friendlyId" TEXT NOT NULL,
"projectId" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "TaskRunTag_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "public"."TaskRunDependency" (
"id" TEXT NOT NULL,
"taskRunId" TEXT NOT NULL,
"checkpointEventId" TEXT,
"dependentAttemptId" TEXT,
"dependentBatchRunId" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"resumedAt" TIMESTAMP(3),
CONSTRAINT "TaskRunDependency_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "public"."TaskRunAttempt" (
"id" TEXT NOT NULL,
"number" INTEGER NOT NULL DEFAULT 0,
"friendlyId" TEXT NOT NULL,
"taskRunId" TEXT NOT NULL,
"backgroundWorkerId" TEXT NOT NULL,
"backgroundWorkerTaskId" TEXT NOT NULL,
"runtimeEnvironmentId" TEXT NOT NULL,
"queueId" TEXT NOT NULL,
"status" "public"."TaskRunAttemptStatus" NOT NULL DEFAULT 'PENDING',
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"startedAt" TIMESTAMP(3),
"completedAt" TIMESTAMP(3),
"usageDurationMs" INTEGER NOT NULL DEFAULT 0,
"error" JSONB,
"output" TEXT,
"outputType" TEXT NOT NULL DEFAULT 'application/json',
CONSTRAINT "TaskRunAttempt_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "public"."BatchTaskRun" (
"id" TEXT NOT NULL,
"friendlyId" TEXT NOT NULL,
"idempotencyKey" TEXT,
"idempotencyKeyExpiresAt" TIMESTAMP(3),
"status" "public"."BatchTaskRunStatus" NOT NULL DEFAULT 'PENDING',
"runtimeEnvironmentId" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"runIds" TEXT[] DEFAULT ARRAY[]::TEXT[],
"runCount" INTEGER NOT NULL DEFAULT 0,
"payload" TEXT,
"payloadType" TEXT NOT NULL DEFAULT 'application/json',
"options" JSONB,
"batchVersion" TEXT NOT NULL DEFAULT 'v1',
"sealed" BOOLEAN NOT NULL DEFAULT false,
"sealedAt" TIMESTAMP(3),
"expectedCount" INTEGER NOT NULL DEFAULT 0,
"completedCount" INTEGER NOT NULL DEFAULT 0,
"completedAt" TIMESTAMP(3),
"resumedAt" TIMESTAMP(3),
"processingJobsCount" INTEGER NOT NULL DEFAULT 0,
"processingJobsExpectedCount" INTEGER NOT NULL DEFAULT 0,
"oneTimeUseToken" TEXT,
"processingStartedAt" TIMESTAMP(3),
"processingCompletedAt" TIMESTAMP(3),
"successfulRunCount" INTEGER,
"failedRunCount" INTEGER,
"taskIdentifier" TEXT,
"checkpointEventId" TEXT,
"dependentTaskAttemptId" TEXT,
CONSTRAINT "BatchTaskRun_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "public"."BatchTaskRunItem" (
"id" TEXT NOT NULL,
"status" "public"."BatchTaskRunItemStatus" NOT NULL DEFAULT 'PENDING',
"batchTaskRunId" TEXT NOT NULL,
"taskRunId" TEXT NOT NULL,
"taskRunAttemptId" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"completedAt" TIMESTAMP(3),
CONSTRAINT "BatchTaskRunItem_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "public"."BatchTaskRunError" (
"id" TEXT NOT NULL,
"batchTaskRunId" TEXT NOT NULL,
"index" INTEGER NOT NULL,
"taskIdentifier" TEXT NOT NULL,
"payload" TEXT,
"options" JSONB,
"error" TEXT NOT NULL,
"errorCode" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "BatchTaskRunError_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "public"."Checkpoint" (
"id" TEXT NOT NULL,
"friendlyId" TEXT NOT NULL,
"type" "public"."CheckpointType" NOT NULL,
"location" TEXT NOT NULL,
"imageRef" TEXT NOT NULL,
"reason" TEXT,
"metadata" TEXT,
"runId" TEXT NOT NULL,
"attemptId" TEXT NOT NULL,
"attemptNumber" INTEGER,
"projectId" TEXT NOT NULL,
"runtimeEnvironmentId" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "Checkpoint_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "public"."CheckpointRestoreEvent" (
"id" TEXT NOT NULL,
"type" "public"."CheckpointRestoreEventType" NOT NULL,
"reason" TEXT,
"metadata" TEXT,
"checkpointId" TEXT NOT NULL,
"runId" TEXT NOT NULL,
"attemptId" TEXT NOT NULL,
"projectId" TEXT NOT NULL,
"runtimeEnvironmentId" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "CheckpointRestoreEvent_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "TaskRun_friendlyId_key" ON "public"."TaskRun"("friendlyId");
-- CreateIndex
CREATE INDEX "TaskRun_parentTaskRunId_idx" ON "public"."TaskRun"("parentTaskRunId");
-- CreateIndex
CREATE INDEX "TaskRun_spanId_idx" ON "public"."TaskRun"("spanId");
-- CreateIndex
CREATE INDEX "TaskRun_parentSpanId_idx" ON "public"."TaskRun"("parentSpanId");
-- CreateIndex
CREATE INDEX "TaskRun_runTags_idx" ON "public"."TaskRun" USING GIN ("runTags" array_ops);
-- CreateIndex
CREATE INDEX "TaskRun_runtimeEnvironmentId_batchId_idx" ON "public"."TaskRun"("runtimeEnvironmentId", "batchId");
-- CreateIndex
CREATE INDEX "TaskRun_runtimeEnvironmentId_createdAt_idx" ON "public"."TaskRun"("runtimeEnvironmentId", "createdAt" DESC);
-- CreateIndex
CREATE INDEX "TaskRun_createdAt_idx" ON "public"."TaskRun" USING BRIN ("createdAt");
-- CreateIndex
CREATE UNIQUE INDEX "TaskRun_oneTimeUseToken_key" ON "public"."TaskRun"("oneTimeUseToken");
-- CreateIndex
CREATE UNIQUE INDEX "TaskRun_runtimeEnvironmentId_taskIdentifier_idempotencyKey_key" ON "public"."TaskRun"("runtimeEnvironmentId", "taskIdentifier", "idempotencyKey");
-- CreateIndex
CREATE INDEX "TaskRunExecutionSnapshot_runId_isValid_createdAt_idx" ON "public"."TaskRunExecutionSnapshot"("runId", "isValid", "createdAt" DESC);
-- CreateIndex
CREATE UNIQUE INDEX "TaskRunCheckpoint_friendlyId_key" ON "public"."TaskRunCheckpoint"("friendlyId");
-- CreateIndex
CREATE UNIQUE INDEX "Waitpoint_friendlyId_key" ON "public"."Waitpoint"("friendlyId");
-- CreateIndex
CREATE UNIQUE INDEX "Waitpoint_completedByTaskRunId_key" ON "public"."Waitpoint"("completedByTaskRunId");
-- CreateIndex
CREATE INDEX "Waitpoint_completedByBatchId_idx" ON "public"."Waitpoint"("completedByBatchId");
-- CreateIndex
CREATE INDEX "Waitpoint_environmentId_type_createdAt_idx" ON "public"."Waitpoint"("environmentId", "type", "createdAt" DESC);
-- CreateIndex
CREATE INDEX "Waitpoint_environmentId_type_status_idx" ON "public"."Waitpoint"("environmentId", "type", "status");
-- CreateIndex
CREATE INDEX "Waitpoint_environmentId_type_id_idx" ON "public"."Waitpoint"("environmentId", "type", "id" DESC);
-- CreateIndex
CREATE UNIQUE INDEX "Waitpoint_environmentId_idempotencyKey_key" ON "public"."Waitpoint"("environmentId", "idempotencyKey");
-- CreateIndex
CREATE INDEX "TaskRunWaitpoint_taskRunId_idx" ON "public"."TaskRunWaitpoint"("taskRunId");
-- CreateIndex
CREATE INDEX "TaskRunWaitpoint_waitpointId_idx" ON "public"."TaskRunWaitpoint"("waitpointId");
-- CreateIndex
CREATE UNIQUE INDEX "TaskRunWaitpoint_taskRunId_waitpointId_batchIndex_key" ON "public"."TaskRunWaitpoint"("taskRunId", "waitpointId", "batchIndex");
-- CreateIndex
CREATE INDEX "WaitpointRunConnection_taskRunId_idx" ON "public"."WaitpointRunConnection"("taskRunId");
-- CreateIndex
CREATE INDEX "WaitpointRunConnection_waitpointId_idx" ON "public"."WaitpointRunConnection"("waitpointId");
-- CreateIndex
CREATE UNIQUE INDEX "WaitpointRunConnection_taskRunId_waitpointId_key" ON "public"."WaitpointRunConnection"("taskRunId", "waitpointId");
-- CreateIndex
CREATE INDEX "CompletedWaitpoint_snapshotId_idx" ON "public"."CompletedWaitpoint"("snapshotId");
-- CreateIndex
CREATE INDEX "CompletedWaitpoint_waitpointId_idx" ON "public"."CompletedWaitpoint"("waitpointId");
-- CreateIndex
CREATE UNIQUE INDEX "CompletedWaitpoint_snapshotId_waitpointId_key" ON "public"."CompletedWaitpoint"("snapshotId", "waitpointId");
-- CreateIndex
CREATE UNIQUE INDEX "WaitpointTag_environmentId_name_key" ON "public"."WaitpointTag"("environmentId", "name");
-- CreateIndex
CREATE UNIQUE INDEX "TaskRunTag_friendlyId_key" ON "public"."TaskRunTag"("friendlyId");
-- CreateIndex
CREATE INDEX "TaskRunTag_name_id_idx" ON "public"."TaskRunTag"("name", "id");
-- CreateIndex
CREATE UNIQUE INDEX "TaskRunTag_projectId_name_key" ON "public"."TaskRunTag"("projectId", "name");
-- CreateIndex
CREATE UNIQUE INDEX "TaskRunDependency_taskRunId_key" ON "public"."TaskRunDependency"("taskRunId");
-- CreateIndex
CREATE UNIQUE INDEX "TaskRunDependency_checkpointEventId_key" ON "public"."TaskRunDependency"("checkpointEventId");
-- CreateIndex
CREATE INDEX "TaskRunDependency_dependentAttemptId_idx" ON "public"."TaskRunDependency"("dependentAttemptId");
-- CreateIndex
CREATE INDEX "TaskRunDependency_dependentBatchRunId_idx" ON "public"."TaskRunDependency"("dependentBatchRunId");
-- CreateIndex
CREATE UNIQUE INDEX "TaskRunAttempt_friendlyId_key" ON "public"."TaskRunAttempt"("friendlyId");
-- CreateIndex
CREATE INDEX "TaskRunAttempt_taskRunId_idx" ON "public"."TaskRunAttempt"("taskRunId");
-- CreateIndex
CREATE UNIQUE INDEX "TaskRunAttempt_taskRunId_number_key" ON "public"."TaskRunAttempt"("taskRunId", "number");
-- CreateIndex
CREATE UNIQUE INDEX "BatchTaskRun_friendlyId_key" ON "public"."BatchTaskRun"("friendlyId");
-- CreateIndex
CREATE UNIQUE INDEX "BatchTaskRun_checkpointEventId_key" ON "public"."BatchTaskRun"("checkpointEventId");
-- CreateIndex
CREATE INDEX "BatchTaskRun_dependentTaskAttemptId_idx" ON "public"."BatchTaskRun"("dependentTaskAttemptId");
-- CreateIndex
CREATE INDEX "BatchTaskRun_runtimeEnvironmentId_id_idx" ON "public"."BatchTaskRun"("runtimeEnvironmentId", "id" DESC);
-- CreateIndex
CREATE UNIQUE INDEX "BatchTaskRun_oneTimeUseToken_key" ON "public"."BatchTaskRun"("oneTimeUseToken");
-- CreateIndex
CREATE UNIQUE INDEX "BatchTaskRun_runtimeEnvironmentId_idempotencyKey_key" ON "public"."BatchTaskRun"("runtimeEnvironmentId", "idempotencyKey");
-- CreateIndex
CREATE INDEX "idx_batchtaskrunitem_taskrunattempt" ON "public"."BatchTaskRunItem"("taskRunAttemptId");
-- CreateIndex
CREATE INDEX "idx_batchtaskrunitem_taskrun" ON "public"."BatchTaskRunItem"("taskRunId");
-- CreateIndex
CREATE UNIQUE INDEX "BatchTaskRunItem_batchTaskRunId_taskRunId_key" ON "public"."BatchTaskRunItem"("batchTaskRunId", "taskRunId");
-- CreateIndex
CREATE INDEX "BatchTaskRunError_batchTaskRunId_idx" ON "public"."BatchTaskRunError"("batchTaskRunId");
-- CreateIndex
CREATE UNIQUE INDEX "BatchTaskRunError_batchTaskRunId_index_key" ON "public"."BatchTaskRunError"("batchTaskRunId", "index");
-- CreateIndex
CREATE UNIQUE INDEX "Checkpoint_friendlyId_key" ON "public"."Checkpoint"("friendlyId");
-- CreateIndex
CREATE INDEX "Checkpoint_attemptId_idx" ON "public"."Checkpoint"("attemptId");
-- CreateIndex
CREATE INDEX "Checkpoint_runId_idx" ON "public"."Checkpoint"("runId");
-- CreateIndex
CREATE INDEX "CheckpointRestoreEvent_checkpointId_idx" ON "public"."CheckpointRestoreEvent"("checkpointId");
-- CreateIndex
CREATE INDEX "CheckpointRestoreEvent_runId_idx" ON "public"."CheckpointRestoreEvent"("runId");
-- AddForeignKey
ALTER TABLE "public"."TaskRun" ADD CONSTRAINT "TaskRun_rootTaskRunId_fkey" FOREIGN KEY ("rootTaskRunId") REFERENCES "public"."TaskRun"("id") ON DELETE SET NULL ON UPDATE NO ACTION;
-- AddForeignKey
ALTER TABLE "public"."TaskRun" ADD CONSTRAINT "TaskRun_parentTaskRunId_fkey" FOREIGN KEY ("parentTaskRunId") REFERENCES "public"."TaskRun"("id") ON DELETE SET NULL ON UPDATE NO ACTION;
-- AddForeignKey
ALTER TABLE "public"."TaskRun" ADD CONSTRAINT "TaskRun_parentTaskRunAttemptId_fkey" FOREIGN KEY ("parentTaskRunAttemptId") REFERENCES "public"."TaskRunAttempt"("id") ON DELETE SET NULL ON UPDATE NO ACTION;
-- AddForeignKey
ALTER TABLE "public"."TaskRun" ADD CONSTRAINT "TaskRun_batchId_fkey" FOREIGN KEY ("batchId") REFERENCES "public"."BatchTaskRun"("id") ON DELETE SET NULL ON UPDATE NO ACTION;
-- AddForeignKey
ALTER TABLE "public"."TaskRunExecutionSnapshot" ADD CONSTRAINT "TaskRunExecutionSnapshot_runId_fkey" FOREIGN KEY ("runId") REFERENCES "public"."TaskRun"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "public"."TaskRunExecutionSnapshot" ADD CONSTRAINT "TaskRunExecutionSnapshot_checkpointId_fkey" FOREIGN KEY ("checkpointId") REFERENCES "public"."TaskRunCheckpoint"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "public"."TaskRunDependency" ADD CONSTRAINT "TaskRunDependency_taskRunId_fkey" FOREIGN KEY ("taskRunId") REFERENCES "public"."TaskRun"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "public"."TaskRunDependency" ADD CONSTRAINT "TaskRunDependency_checkpointEventId_fkey" FOREIGN KEY ("checkpointEventId") REFERENCES "public"."CheckpointRestoreEvent"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "public"."TaskRunDependency" ADD CONSTRAINT "TaskRunDependency_dependentAttemptId_fkey" FOREIGN KEY ("dependentAttemptId") REFERENCES "public"."TaskRunAttempt"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "public"."TaskRunDependency" ADD CONSTRAINT "TaskRunDependency_dependentBatchRunId_fkey" FOREIGN KEY ("dependentBatchRunId") REFERENCES "public"."BatchTaskRun"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "public"."TaskRunAttempt" ADD CONSTRAINT "TaskRunAttempt_taskRunId_fkey" FOREIGN KEY ("taskRunId") REFERENCES "public"."TaskRun"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "public"."BatchTaskRun" ADD CONSTRAINT "BatchTaskRun_checkpointEventId_fkey" FOREIGN KEY ("checkpointEventId") REFERENCES "public"."CheckpointRestoreEvent"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "public"."BatchTaskRun" ADD CONSTRAINT "BatchTaskRun_dependentTaskAttemptId_fkey" FOREIGN KEY ("dependentTaskAttemptId") REFERENCES "public"."TaskRunAttempt"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "public"."BatchTaskRunItem" ADD CONSTRAINT "BatchTaskRunItem_batchTaskRunId_fkey" FOREIGN KEY ("batchTaskRunId") REFERENCES "public"."BatchTaskRun"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "public"."BatchTaskRunItem" ADD CONSTRAINT "BatchTaskRunItem_taskRunId_fkey" FOREIGN KEY ("taskRunId") REFERENCES "public"."TaskRun"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "public"."BatchTaskRunItem" ADD CONSTRAINT "BatchTaskRunItem_taskRunAttemptId_fkey" FOREIGN KEY ("taskRunAttemptId") REFERENCES "public"."TaskRunAttempt"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "public"."BatchTaskRunError" ADD CONSTRAINT "BatchTaskRunError_batchTaskRunId_fkey" FOREIGN KEY ("batchTaskRunId") REFERENCES "public"."BatchTaskRun"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "public"."Checkpoint" ADD CONSTRAINT "Checkpoint_runId_fkey" FOREIGN KEY ("runId") REFERENCES "public"."TaskRun"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "public"."Checkpoint" ADD CONSTRAINT "Checkpoint_attemptId_fkey" FOREIGN KEY ("attemptId") REFERENCES "public"."TaskRunAttempt"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "public"."CheckpointRestoreEvent" ADD CONSTRAINT "CheckpointRestoreEvent_checkpointId_fkey" FOREIGN KEY ("checkpointId") REFERENCES "public"."Checkpoint"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "public"."CheckpointRestoreEvent" ADD CONSTRAINT "CheckpointRestoreEvent_runId_fkey" FOREIGN KEY ("runId") REFERENCES "public"."TaskRun"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "public"."CheckpointRestoreEvent" ADD CONSTRAINT "CheckpointRestoreEvent_attemptId_fkey" FOREIGN KEY ("attemptId") REFERENCES "public"."TaskRunAttempt"("id") ON DELETE CASCADE ON UPDATE CASCADE;
@@ -0,0 +1,5 @@
-- Partial unique index (Prisma cannot express the WHERE clause, so it is SQL-only). Mirrors the
-- control-plane `TaskRunWaitpoint_taskRunId_waitpointId_batchIndex_null_key`: without it the
-- composite (taskRunId, waitpointId, batchIndex) index treats NULL batchIndex rows as distinct, so
-- blockRunWithWaitpointEdges' ON CONFLICT DO NOTHING cannot dedupe a re-blocked NULL-batchIndex edge.
CREATE UNIQUE INDEX "TaskRunWaitpoint_taskRunId_waitpointId_batchIndex_null_key" ON "public"."TaskRunWaitpoint"("taskRunId", "waitpointId") WHERE "batchIndex" IS NULL;
@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (e.g., Git)
provider = "postgresql"
@@ -0,0 +1,264 @@
import { describe, expect, it } from "vitest";
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
// Parses both the control-plane schema (`@trigger.dev/database`) and this
// dedicated run-ops schema, then diffs every SCALAR field of each run-subgraph
// model BIDIRECTIONALLY: a field present in either schema must exist in the
// other with matching type/nullability/array-ness/`@default`, since a run row
// must be writable to either physical database.
//
// Relation fields are excluded by design: the dedicated schema drops
// control-plane `@relation`s to control-plane-owned models and replaces the
// implicit many-to-many waitpoint relations with explicit FK-free join models
// (`TaskRunWaitpoint`, `WaitpointRunConnection`, `CompletedWaitpoint`). Only
// the scalar FK columns backing those relations (e.g. `projectId`) are
// compared; the relation object fields (e.g. `project`) are skipped.
const CONTROL_PLANE_SCHEMA_PATH = "../../database/prisma/schema.prisma";
const DEDICATED_SCHEMA_PATH = "./schema.prisma";
// Must never appear as a relation target in the dedicated schema.
const CONTROL_PLANE_ONLY_MODELS = [
"Organization",
"OrgMember",
"Project",
"RuntimeEnvironment",
"User",
"TaskSchedule",
"BackgroundWorker",
"BackgroundWorkerTask",
"WorkerDeployment",
"TaskQueue",
];
// Must have every scalar column reproduced in the dedicated schema.
const RUN_SUBGRAPH_MODELS = [
"TaskRun",
"TaskRunAttempt",
"TaskRunExecutionSnapshot",
"TaskRunWaitpoint",
"TaskRunCheckpoint",
"CheckpointRestoreEvent",
"TaskRunTag",
"Waitpoint",
"WaitpointTag",
"BatchTaskRun",
"TaskRunDependency",
"BatchTaskRunItem",
"BatchTaskRunError",
"Checkpoint",
];
function readSchema(rel: string): string {
return readFileSync(resolve(__dirname, rel), "utf8");
}
// Strips `/* */` block comments and `//`/`///` line comments so prose mentioning
// model names can't false-match below. (Neither schema has `/*` inside a string.)
function stripComments(schema: string): string {
return schema.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "");
}
type FieldInfo = {
type: string;
optional: boolean;
array: boolean;
default: string | null;
};
type ModelFields = Map<string, FieldInfo>;
// Prisma model blocks don't nest, so a lazy match to the next `}`-only line suffices.
function extractModelBlocks(schema: string): Map<string, string> {
const blocks = new Map<string, string>();
const re = /^model\s+(\w+)\s*\{([\s\S]*?)\n\}/gm;
let match: RegExpExecArray | null;
while ((match = re.exec(schema))) {
blocks.set(match[1], match[2]);
}
return blocks;
}
// Raw argument of `@default(...)`, honoring nested parens (`@default(cuid())`). Null if absent.
function extractDefault(attrs: string): string | null {
const marker = "@default(";
const idx = attrs.indexOf(marker);
if (idx === -1) return null;
const start = idx + marker.length;
let depth = 0;
for (let i = start; i < attrs.length; i++) {
if (attrs[i] === "(") {
depth++;
} else if (attrs[i] === ")") {
if (depth === 0) return attrs.slice(start, i);
depth--;
}
}
return attrs.slice(start);
}
// Excludes relation fields: anything carrying `@relation`, plus back-relation fields
// (e.g. `checkpoints Checkpoint[]`) identified by their type being another model name.
// `unparsed` collects any content line the field regex fails to match, so a future
// multi-line field can never silently vanish from the diff.
function parseScalarFields(
body: string,
modelNames: Set<string>
): { fields: ModelFields; unparsed: string[] } {
const fields: ModelFields = new Map();
const unparsed: string[] = [];
for (const rawLine of body.split("\n")) {
const line = rawLine.trim();
if (!line || line.startsWith("@@")) continue;
const match = line.match(/^(\w+)\s+([A-Za-z_]\w*)(\[\])?(\?)?\s*(.*)$/);
if (!match) {
unparsed.push(line);
continue;
}
const [, name, type, arrayMark, optionalMark, rest] = match;
if (rest.includes("@relation")) continue;
if (modelNames.has(type)) continue;
fields.set(name, {
type,
array: arrayMark === "[]",
optional: optionalMark === "?",
default: extractDefault(rest),
});
}
return { fields, unparsed };
}
function parseSchema(schema: string) {
const stripped = stripComments(schema);
const modelBlocks = extractModelBlocks(stripped);
const modelNames = new Set(modelBlocks.keys());
const models = new Map<string, ModelFields>();
const unparsed: string[] = [];
for (const [name, body] of modelBlocks) {
const parsed = parseScalarFields(body, modelNames);
models.set(name, parsed.fields);
for (const line of parsed.unparsed) {
unparsed.push(`${name}: ${line}`);
}
}
return { models, modelNames, unparsed };
}
function describeField(field: FieldInfo | undefined): string {
if (!field) return "<missing>";
const array = field.array ? "[]" : "";
const optional = field.optional ? "?" : "";
const withDefault = field.default !== null ? ` @default(${field.default})` : "";
return `${field.type}${array}${optional}${withDefault}`;
}
const controlPlane = parseSchema(readSchema(CONTROL_PLANE_SCHEMA_PATH));
const dedicated = parseSchema(readSchema(DEDICATED_SCHEMA_PATH));
describe("dedicated run-ops schema parity", () => {
it("includes all 14 run-subgraph models in both schemas", () => {
for (const model of RUN_SUBGRAPH_MODELS) {
expect(Array.from(dedicated.modelNames)).toContain(model);
expect(Array.from(controlPlane.modelNames)).toContain(model);
}
});
it("fails on any content line the field parser doesn't recognise (no silent skips)", () => {
// Scope the control-plane check to run-subgraph models so an unrelated control-plane schema
// edit can't break this run-ops test; the dedicated schema contains only run-ops models.
const inRunSubgraph = (entry: string) =>
RUN_SUBGRAPH_MODELS.some((model) => entry.startsWith(`${model}: `));
expect(controlPlane.unparsed.filter(inRunSubgraph)).toEqual([]);
expect(dedicated.unparsed).toEqual([]);
});
it("reproduces every scalar column of each run-subgraph model bidirectionally with matching type/nullability/array/default", () => {
const mismatches: string[] = [];
for (const modelName of RUN_SUBGRAPH_MODELS) {
const controlFields = controlPlane.models.get(modelName);
const dedicatedFields = dedicated.models.get(modelName);
if (!controlFields || !dedicatedFields) {
mismatches.push(`${modelName}: model not found in one of the two schemas`);
continue;
}
const fieldNames = new Set([...controlFields.keys(), ...dedicatedFields.keys()]);
for (const fieldName of fieldNames) {
const controlField = controlFields.get(fieldName);
const dedicatedField = dedicatedFields.get(fieldName);
if (!controlField) {
mismatches.push(
`${modelName}.${fieldName}: dedicated has ${describeField(
dedicatedField
)} but the control-plane schema has no such scalar field`
);
continue;
}
if (!dedicatedField) {
mismatches.push(
`${modelName}.${fieldName}: control-plane has ${describeField(
controlField
)} but the dedicated schema has no such scalar field`
);
continue;
}
const matches =
dedicatedField.type === controlField.type &&
dedicatedField.array === controlField.array &&
dedicatedField.optional === controlField.optional &&
dedicatedField.default === controlField.default;
if (!matches) {
mismatches.push(
`${modelName}.${fieldName}: control-plane=${describeField(
controlField
)} dedicated=${describeField(dedicatedField)}`
);
}
}
}
expect(mismatches).toEqual([]);
});
it("references no control-plane model as a relation target", () => {
const dedicatedText = stripComments(readSchema(DEDICATED_SCHEMA_PATH));
for (const model of CONTROL_PLANE_ONLY_MODELS) {
// A relation target appears as ` fieldName Model @relation(...)`. A bare
// scalar column like `projectId String` is fine; the model TYPE must be absent.
const relationTarget = new RegExp(
`@relation[^\\n]*\\b${model}\\b|\\b${model}\\b[^\\n]*@relation`
);
expect(dedicatedText).not.toMatch(relationTarget);
expect(dedicatedText).not.toMatch(new RegExp(`\\s${model}(\\?|\\[\\])?\\s`));
}
});
it("keeps the group-(A) waitpoint-block references FK-FREE (scalar columns / explicit FK-free join models)", () => {
const dedicatedText = stripComments(readSchema(DEDICATED_SCHEMA_PATH));
// TaskRunWaitpoint must NOT carry a `@relation` to Waitpoint/TaskRun/BatchTaskRun.
const trw = dedicatedText.match(/model TaskRunWaitpoint \{[\s\S]*?\n\}/)![0];
expect(trw).not.toMatch(/@relation/);
expect(trw).toMatch(/waitpointId\s+String/);
expect(trw).toMatch(/taskRunId\s+String/);
// The two implicit M2M sets are replaced by explicit FK-free join models.
expect(dedicatedText).toMatch(/model WaitpointRunConnection \{/);
expect(dedicatedText).toMatch(/model CompletedWaitpoint \{/);
const wrc = dedicatedText.match(/model WaitpointRunConnection \{[\s\S]*?\n\}/)![0];
expect(wrc).not.toMatch(/@relation/);
// Waitpoint completion back-refs are scalar, not relations.
const wp = dedicatedText.match(/model Waitpoint \{[\s\S]*?\n\}/)![0];
expect(wp).not.toMatch(/completedByTaskRun\s+TaskRun\s*\?\s*@relation/);
});
it("keeps the group-(B) co-resident references as real FKs (e.g. TaskRunAttempt.taskRun)", () => {
const dedicatedText = stripComments(readSchema(DEDICATED_SCHEMA_PATH));
const attempt = dedicatedText.match(/model TaskRunAttempt \{[\s\S]*?\n\}/)![0];
// The attempt->run relation stays a real FK (always co-resident).
expect(attempt).toMatch(/taskRun\s+TaskRun\s+@relation/);
});
});
@@ -0,0 +1,981 @@
datasource db {
provider = "postgresql"
url = env("RUN_OPS_DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
output = "../generated/run-ops"
binaryTargets = ["native", "debian-openssl-1.1.x"]
previewFeatures = ["metrics"]
}
// ─────────────────────────────────────────────────────────────────────────────
// Dedicated run-ops database schema.
//
// This schema holds the subset of the control-plane `@trigger.dev/database`
// models that describe a run's lifecycle. Each model reproduces its
// control-plane counterpart column-for-column; the only differences are in how
// relations are handled, according to three rules:
//
// 1. Relations that point at control-plane-owned models (organization,
// project, environment, background worker, queue, and the like) are not
// reproduced. Their foreign-key columns are kept as plain scalars, with no
// `@relation` and no database foreign key, because the referenced rows live
// in the control-plane database.
//
// 2. Waitpoint block and completion relations are foreign-key-free. A block or
// completion edge can connect a run and a waitpoint that live in different
// databases, so it must never be enforced by a foreign key here. These
// relations are represented by scalar columns plus the explicit join models
// `TaskRunWaitpoint`, `WaitpointRunConnection`, and `CompletedWaitpoint`.
// The join models replace implicit many-to-many relations that exist in the
// control-plane schema.
//
// 3. Relations that stay entirely within this database (run to root/parent
// run, run to attempt, run to batch, checkpoints, dependencies, and so on)
// are kept as real foreign keys, exactly as in the control plane.
//
// Relation-only back-references to models outside this subset are dropped; the
// per-model notes below call out where that happens.
// ─────────────────────────────────────────────────────────────────────────────
enum RuntimeEnvironmentType {
PRODUCTION
STAGING
DEVELOPMENT
PREVIEW
}
/// Same columns and indexes as the control-plane `TaskRun`. The environment,
/// project, `lockedBy`, and `lockedToVersion` relations are scalar-only foreign
/// keys here. The waitpoint completion/block relations
/// (`associatedWaitpoint`, `blockedByWaitpoints`, `connectedWaitpoints`) are
/// foreign-key-free: completion lives on `Waitpoint.completedByTaskRunId`, block
/// edges are rows of `TaskRunWaitpoint`, and connections are rows of
/// `WaitpointRunConnection`. The root/parent-run, parent-attempt, and batch
/// relations are kept as real foreign keys. Control-plane back-references to
/// tags, alerts, bulk-action items, and playground conversations are dropped.
model TaskRun {
id String @id @default(cuid())
number Int @default(0)
friendlyId String @unique
engine RunEngineVersion @default(V1)
status TaskRunStatus @default(PENDING)
statusReason String?
idempotencyKey String?
idempotencyKeyExpiresAt DateTime?
/// Stores the user-provided key and scope: { key: string, scope: "run" | "attempt" | "global" }
idempotencyKeyOptions Json?
/// Debounce options: { key: string, delay: string, createdAt: Date }
debounce Json?
taskIdentifier String
isTest Boolean @default(false)
payload String
payloadType String @default("application/json")
context Json?
traceContext Json?
traceId String
spanId String
/// scalar FK (control-plane `runtimeEnvironment` relation)
runtimeEnvironmentId String
environmentType RuntimeEnvironmentType?
/// scalar FK (control-plane `project` relation)
projectId String
organizationId String?
// The specific queue this run is in
queue String
// The queueId is set when the run is locked to a specific queue
lockedQueueId String?
/// The main queue that this run is part of
workerQueue String @default("main") @map("masterQueue")
/// User-facing geo region, stamped at trigger; workerQueue is where it actually ran.
region String?
/// @deprecated
secondaryMasterQueue String?
/// From engine v2+ this will be defined after a run has been dequeued (starting at 1)
attemptNumber Int?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
attempts TaskRunAttempt[] @relation("attempts")
/// Denormized column that holds the raw tags
runTags String[]
/// Denormalized version of the background worker task
taskVersion String?
sdkVersion String?
cliVersion String?
checkpoints Checkpoint[]
/// startedAt marks the point at which a run is dequeued from MarQS
startedAt DateTime?
/// executedAt is set when the first attempt is about to execute
executedAt DateTime?
completedAt DateTime?
machinePreset String?
usageDurationMs Int @default(0)
costInCents Float @default(0)
baseCostInCents Float @default(0)
lockedAt DateTime?
/// scalar FK (control-plane `lockedBy` relation)
lockedById String?
/// scalar FK (control-plane `lockedToVersion` relation)
lockedToVersionId String?
/// The "priority" of the run. This is just a negative offset in ms for the queue timestamp
/// E.g. a value of 60_000 would put the run into the queue 60s ago.
priorityMs Int @default(0)
concurrencyKey String?
delayUntil DateTime?
queuedAt DateTime?
ttl String?
expiredAt DateTime?
maxAttempts Int?
lockedRetryConfig Json?
/// optional token that can be used to authenticate the task run
oneTimeUseToken String?
// The control-plane waitpoint relations (associatedWaitpoint, blockedByWaitpoints,
// connectedWaitpoints) are foreign-key-free here: completion is stored on
// Waitpoint.completedByTaskRunId, block edges are rows of TaskRunWaitpoint, and
// connections are rows of WaitpointRunConnection.
/// Where the logs are stored
taskEventStore String @default("taskEvent")
queueTimestamp DateTime?
batchItems BatchTaskRunItem[]
dependency TaskRunDependency?
CheckpointRestoreEvent CheckpointRestoreEvent[]
executionSnapshots TaskRunExecutionSnapshot[]
scheduleInstanceId String?
scheduleId String?
bulkActionGroupIds String[] @default([])
logsDeletedAt DateTime?
replayedFromTaskRunFriendlyId String?
/// This represents the original task that was triggered outside of a Trigger.dev task
rootTaskRun TaskRun? @relation("TaskRootRun", fields: [rootTaskRunId], references: [id], onDelete: SetNull, onUpdate: NoAction)
rootTaskRunId String?
/// The root run will have a list of all the descendant runs, children, grand children, etc.
descendantRuns TaskRun[] @relation("TaskRootRun")
/// The immediate parent run of this task run
parentTaskRun TaskRun? @relation("TaskParentRun", fields: [parentTaskRunId], references: [id], onDelete: SetNull, onUpdate: NoAction)
parentTaskRunId String?
/// The immediate child runs of this task run
childRuns TaskRun[] @relation("TaskParentRun")
/// The immediate parent attempt of this task run
parentTaskRunAttempt TaskRunAttempt? @relation("TaskParentRunAttempt", fields: [parentTaskRunAttemptId], references: [id], onDelete: SetNull, onUpdate: NoAction)
parentTaskRunAttemptId String?
/// The batch run that this task run is a part of
batch BatchTaskRun? @relation(fields: [batchId], references: [id], onDelete: SetNull, onUpdate: NoAction)
batchId String?
/// whether or not the task run was created because of a triggerAndWait for batchTriggerAndWait
resumeParentOnCompletion Boolean @default(false)
/// The depth of this task run in the task run hierarchy
depth Int @default(0)
/// The span ID of the "trigger" span in the parent task run
parentSpanId String?
/// Holds the state of the run chain for deadlock detection
runChainState Json?
/// seed run metadata
seedMetadata String?
seedMetadataType String @default("application/json")
/// Run metadata
metadata String?
metadataType String @default("application/json")
metadataVersion Int @default(1)
/// Structured annotations: triggerSource, triggerAction, rootTriggerSource, rootScheduleId
annotations Json?
/// Whether the latest attempt was a warm start. Null until first attempt starts.
isWarmStart Boolean?
/// Run output
output String?
outputType String @default("application/json")
/// Run error
error Json?
/// Organization's billing plan type (cached for fallback when billing API fails)
planType String?
maxDurationInSeconds Int?
/// The version of the realtime streams implementation used by the run
realtimeStreamsVersion String @default("v1")
/// Store the stream keys that are being used by the run
realtimeStreams String[] @default([])
/// S2 basin where this run's realtime streams live. Stamped at create
/// time from `Organization.streamBasinName` so reads can resolve the
/// basin without joining org. Null when the org has no per-org basin
/// (OSS, or pre-backfill); reads fall back to the global basin.
streamBasinName String?
@@unique([oneTimeUseToken])
@@unique([runtimeEnvironmentId, taskIdentifier, idempotencyKey])
// Finding child runs
@@index([parentTaskRunId])
// Run page inspector
@@index([spanId])
@@index([parentSpanId])
// Finding runs in a batch
@@index([runTags(ops: ArrayOps)], type: Gin)
@@index([runtimeEnvironmentId, batchId])
@@index([runtimeEnvironmentId, createdAt(sort: Desc)])
@@index([createdAt], type: Brin)
}
enum TaskRunStatus {
///
/// NON-FINAL STATUSES
///
/// Task has been scheduled to run in the future
DELAYED
/// Task is waiting to be executed by a worker
PENDING
/// The run is pending a version update because it cannot execute without additional information (task, queue, etc.). Replaces WAITING_FOR_DEPLOY
PENDING_VERSION
/// Task hasn't been deployed yet but is waiting to be executed. Deprecated in favor of PENDING_VERSION
WAITING_FOR_DEPLOY
/// Task has been dequeued from the queue but is not yet executing
DEQUEUED
/// Task is currently being executed by a worker
EXECUTING
/// Task has been paused by the system, and will be resumed by the system
WAITING_TO_RESUME
/// Task has failed and is waiting to be retried
RETRYING_AFTER_FAILURE
/// Task has been paused by the user, and can be resumed by the user
PAUSED
///
/// FINAL STATUSES
///
/// Task has been canceled by the user
CANCELED
/// Task was interrupted during execution, mostly this happens in development environments
INTERRUPTED
/// Task has been completed successfully
COMPLETED_SUCCESSFULLY
/// Task has been completed with errors
COMPLETED_WITH_ERRORS
/// Task has failed to complete, due to an error in the system
SYSTEM_FAILURE
/// Task has crashed and won't be retried, most likely the worker ran out of resources, e.g. memory or storage
CRASHED
/// Task reached the ttl without being executed
EXPIRED
/// Task has been timed out when using maxDuration
TIMED_OUT
}
enum RunEngineVersion {
/// The original version that uses marqs v1 and Graphile
V1
V2
}
/// Used by the RunEngine during TaskRun execution
/// It has the required information to transactionally progress a run through states,
/// and prevent side effects like heartbeats failing a run that has progressed.
/// It is optimised for performance and is designed to be cleared at some point,
/// so there are no cascading relationships to other models.
///
/// Same columns and indexes as the control-plane version. The `run` and
/// `checkpoint` relations are kept as real foreign keys. The `completedWaitpoints`
/// relation is foreign-key-free: it is represented by rows of the `CompletedWaitpoint`
/// join model instead.
model TaskRunExecutionSnapshot {
id String @id @default(cuid())
/// This should always be 2+ (V1 didn't use the run engine or snapshots)
engine RunEngineVersion @default(V2)
/// The execution status
executionStatus TaskRunExecutionStatus
/// For debugging
description String
/// We store invalid snapshots as a record of the run state when we tried to move
isValid Boolean @default(true)
error String?
/// The previous snapshot ID
previousSnapshotId String?
/// Run
runId String
run TaskRun @relation(fields: [runId], references: [id])
runStatus TaskRunStatus
// Batch
batchId String?
/// This is the current run attempt number. Users can define how many attempts they want for a run.
attemptNumber Int?
/// Environment
environmentId String
environmentType RuntimeEnvironmentType
projectId String
organizationId String
// The control-plane `completedWaitpoints` relation (waitpoints completed for this
// execution) is foreign-key-free here, stored as rows of CompletedWaitpoint.
/// An array of waitpoint IDs in the correct order, used for batches
completedWaitpointOrder String[]
/// Checkpoint
checkpointId String?
checkpoint TaskRunCheckpoint? @relation(fields: [checkpointId], references: [id])
/// Worker
workerId String?
runnerId String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
lastHeartbeatAt DateTime?
/// Metadata used by various systems in the run engine
metadata Json?
/// Used to get the latest valid snapshot quickly
@@index([runId, isValid, createdAt(sort: Desc)])
}
enum TaskRunExecutionStatus {
/// Run has been created
RUN_CREATED
/// Run is delayed, waiting to be enqueued
DELAYED
/// Run is in the RunQueue
QUEUED
/// Run is in the RunQueue, and is also executing. This happens when a run is continued cannot reacquire concurrency
QUEUED_EXECUTING
/// Run has been pulled from the queue, but isn't executing yet
PENDING_EXECUTING
/// Run is executing on a worker
EXECUTING
/// Run is executing on a worker but is waiting for waitpoints to complete
EXECUTING_WITH_WAITPOINTS
/// Run has been suspended and may be waiting for waitpoints to complete before resuming
SUSPENDED
/// Run has been scheduled for cancellation
PENDING_CANCEL
/// Run is finished (success of failure)
FINISHED
}
/// Same columns as the control-plane version, with the project and environment
/// relations kept as scalar-only foreign keys.
model TaskRunCheckpoint {
id String @id @default(cuid())
friendlyId String @unique
type TaskRunCheckpointType
location String
imageRef String?
reason String?
metadata String?
/// scalar FK (control-plane `project` relation)
projectId String
/// scalar FK (control-plane `runtimeEnvironment` relation)
runtimeEnvironmentId String
executionSnapshot TaskRunExecutionSnapshot[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
enum TaskRunCheckpointType {
DOCKER
KUBERNETES
COMPUTE
}
/// A Waitpoint blocks a run from continuing until it's completed
/// If there's a waitpoint blocking a run, it shouldn't be in the queue
///
/// Same columns and indexes as the control-plane version. Every relation is
/// foreign-key-free, because a waitpoint and the run or batch it references may
/// live in different databases: `completedByTaskRunId` and `completedByBatchId`
/// are scalar-only, and the `blockingTaskRuns`, `connectedRuns`, and
/// `completedExecutionSnapshots` back-references are represented by the
/// `TaskRunWaitpoint`, `WaitpointRunConnection`, and `CompletedWaitpoint` join
/// models. The project and environment relations are scalar-only foreign keys.
model Waitpoint {
id String @id @default(cuid())
friendlyId String @unique
type WaitpointType
status WaitpointStatus @default(PENDING)
completedAt DateTime?
/// If it's an Event type waitpoint, this is the event. It can also be provided for the DATETIME type
idempotencyKey String
/// If this is true then we can show it in the dashboard/return it from the SDK
userProvidedIdempotencyKey Boolean
/// If there's a user provided idempotency key, this is the time it expires at
idempotencyKeyExpiresAt DateTime?
/// If an idempotencyKey is no longer active, we store it here and generate a new one for the idempotencyKey field.
/// Clearing an idempotencyKey is useful for debounce or cancelling child runs.
/// This is a workaround because Prisma doesn't support partial indexes.
inactiveIdempotencyKey String?
/// If it's a RUN type waitpoint, this is the associated run.
/// scalar FK (control-plane `completedByTaskRun` relation)
completedByTaskRunId String? @unique
/// If it's a DATETIME type waitpoint, this is the date.
/// If it's a MANUAL waitpoint, this can be set as the `timeout`.
completedAfter DateTime?
/// If it's a BATCH type waitpoint, this is the associated batch.
/// scalar FK (control-plane `completedByBatch` relation)
completedByBatchId String?
/// When completed, an output can be stored here
output String?
outputType String @default("application/json")
outputIsError Boolean @default(false)
/// scalar FK (control-plane `project` relation)
projectId String
/// scalar FK (control-plane `environment` relation)
environmentId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
/// Denormized column that holds the raw tags
/// Denormalized column that holds the raw tags
tags String[]
/// Quickly find an idempotent waitpoint
@@unique([environmentId, idempotencyKey])
/// Quickly find a batch waitpoint
@@index([completedByBatchId])
/// Used on the Waitpoint dashboard pages
/// Time period filtering
@@index([environmentId, type, createdAt(sort: Desc)])
/// Status filtering
@@index([environmentId, type, status])
/// For the waitpoint token dashboard page
@@index([environmentId, type, id(sort: Desc)])
}
enum WaitpointType {
RUN
DATETIME
MANUAL
BATCH
}
enum WaitpointStatus {
PENDING
COMPLETED
}
/// The block edge between a run and a waitpoint. Same columns and indexes as the
/// control-plane version, but the run, waitpoint, project, and batch relations
/// are all scalar-only foreign keys: a block edge can connect a run and a
/// waitpoint that live in different databases, so it is never enforced by a
/// foreign key here.
model TaskRunWaitpoint {
id String @id @default(cuid())
/// scalar FK (control-plane `taskRun` relation)
taskRunId String
/// scalar FK (control-plane `waitpoint` relation)
waitpointId String
/// scalar FK (control-plane `project` relation)
projectId String
/// This span id is completed when the waitpoint is completed. This is used with cached runs (idempotent)
spanIdToComplete String?
/// scalar FK (control-plane `batch` relation)
batchId String?
//if there's an associated batch and this isn't set it's for the entire batch
//if it is set, it's a specific run in the batch
batchIndex Int?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
/// There are two constraints, the one below and also one that Prisma doesn't support
/// The second one implemented in SQL only prevents a TaskRun + Waitpoint with a null batchIndex
@@unique([taskRunId, waitpointId, batchIndex])
@@index([taskRunId])
@@index([waitpointId])
}
/// Explicit join model for the connection between a run and every waitpoint that
/// blocked it (kept for display). This has no control-plane counterpart table: it
/// replaces the implicit many-to-many relation between `TaskRun.connectedWaitpoints`
/// and `Waitpoint.connectedRuns`. Scalar columns only, no foreign keys, so a
/// connection can span both databases.
model WaitpointRunConnection {
id String @id @default(cuid())
taskRunId String
waitpointId String
@@unique([taskRunId, waitpointId])
@@index([taskRunId])
@@index([waitpointId])
}
/// Explicit join model recording which waitpoints an execution snapshot completed.
/// This has no control-plane counterpart table: it replaces the implicit
/// many-to-many relation between `TaskRunExecutionSnapshot.completedWaitpoints`
/// and `Waitpoint`. Scalar columns only, no foreign keys, so a snapshot may record
/// a waitpoint that lives in the other database.
model CompletedWaitpoint {
id String @id @default(cuid())
snapshotId String
waitpointId String
@@unique([snapshotId, waitpointId])
@@index([snapshotId])
@@index([waitpointId])
}
/// Same columns and indexes as the control-plane version, with the environment
/// and project relations kept as scalar-only foreign keys.
model WaitpointTag {
id String @id @default(cuid())
name String
/// scalar FK (control-plane `environment` relation)
environmentId String
/// scalar FK (control-plane `project` relation)
projectId String
createdAt DateTime @default(now())
@@unique([environmentId, name])
}
/// Same columns and indexes as the control-plane version, with the project
/// relation kept as a scalar-only foreign key. The control-plane `runs` back-
/// reference (the tag-to-run many-to-many) is dropped.
model TaskRunTag {
id String @id @default(cuid())
name String
friendlyId String @unique
/// scalar FK (control-plane `project` relation)
projectId String
createdAt DateTime @default(now())
@@unique([projectId, name])
//Makes run filtering by tag faster
@@index([name, id])
}
/// This is used for triggerAndWait and batchTriggerAndWait. The taskRun is the child task, it points at a parent attempt or a batch
///
/// Identical to the control-plane version: every relation stays within this
/// database and is kept as a real foreign key.
model TaskRunDependency {
id String @id @default(cuid())
/// The child run
taskRun TaskRun @relation(fields: [taskRunId], references: [id], onDelete: Cascade, onUpdate: Cascade)
taskRunId String @unique
checkpointEvent CheckpointRestoreEvent? @relation(fields: [checkpointEventId], references: [id], onDelete: Cascade, onUpdate: Cascade)
checkpointEventId String? @unique
/// An attempt that is dependent on this task run.
dependentAttempt TaskRunAttempt? @relation(fields: [dependentAttemptId], references: [id])
dependentAttemptId String?
/// A batch run that is dependent on this task run
dependentBatchRun BatchTaskRun? @relation("dependentBatchRun", fields: [dependentBatchRunId], references: [id])
dependentBatchRunId String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
resumedAt DateTime?
@@index([dependentAttemptId])
@@index([dependentBatchRunId])
}
/// Same columns and indexes as the control-plane version. The owning-run relation
/// is kept as a real foreign key. The background-worker, background-worker-task,
/// environment, and queue relations are scalar-only foreign keys. The control-
/// plane `alerts` back-reference is dropped.
model TaskRunAttempt {
id String @id @default(cuid())
number Int @default(0)
friendlyId String @unique
/// The owning run
taskRun TaskRun @relation("attempts", fields: [taskRunId], references: [id], onDelete: Cascade, onUpdate: Cascade)
taskRunId String
/// scalar FK (control-plane `backgroundWorker` relation)
backgroundWorkerId String
/// scalar FK (control-plane `backgroundWorkerTask` relation)
backgroundWorkerTaskId String
/// scalar FK (control-plane `runtimeEnvironment` relation)
runtimeEnvironmentId String
/// scalar FK (control-plane `queue` relation)
queueId String
status TaskRunAttemptStatus @default(PENDING)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
startedAt DateTime?
completedAt DateTime?
usageDurationMs Int @default(0)
error Json?
output String?
outputType String @default("application/json")
dependencies TaskRunDependency[]
batchDependencies BatchTaskRun[]
checkpoints Checkpoint[]
batchTaskRunItems BatchTaskRunItem[]
CheckpointRestoreEvent CheckpointRestoreEvent[]
childRuns TaskRun[] @relation("TaskParentRunAttempt")
@@unique([taskRunId, number])
@@index([taskRunId])
}
enum TaskRunAttemptStatus {
/// NON-FINAL
PENDING
EXECUTING
PAUSED
/// FINAL
FAILED
CANCELED
COMPLETED
}
/// Same columns and indexes as the control-plane version. The environment
/// relation is a scalar-only foreign key. The `runsBlocked` and `waitpoints`
/// back-references are foreign-key-free: block edges are rows of
/// `TaskRunWaitpoint`, and batch-completed waitpoints are found via
/// `Waitpoint.completedByBatchId`. The `runs`, `errors`, `items`,
/// `checkpointEvent`, `dependentTaskAttempt`, and `runDependencies` relations
/// stay within this database and are kept as real foreign keys.
model BatchTaskRun {
id String @id @default(cuid())
friendlyId String @unique
idempotencyKey String?
idempotencyKeyExpiresAt DateTime?
status BatchTaskRunStatus @default(PENDING)
/// scalar FK (control-plane `runtimeEnvironment` relation)
runtimeEnvironmentId String
/// This only includes new runs, not idempotent runs.
runs TaskRun[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// new columns
/// Friendly IDs
runIds String[] @default([])
runCount Int @default(0)
payload String?
payloadType String @default("application/json")
options Json?
batchVersion String @default("v1")
//engine v2
// The control-plane `runsBlocked` and `waitpoints` back-references are foreign-
// key-free here: block edges are rows of TaskRunWaitpoint keyed by batchId, and
// batch-completed waitpoints are found via Waitpoint.completedByBatchId.
// This is for v3 batches
/// sealed is set to true once no more items can be added to the batch
sealed Boolean @default(false)
sealedAt DateTime?
/// this is the expected number of items in the batch
expectedCount Int @default(0)
/// this is the completed number of items in the batch. once this reaches expectedCount, and the batch is sealed, the batch is considered completed
completedCount Int @default(0)
completedAt DateTime?
resumedAt DateTime?
/// this is used to be able to "seal" this BatchTaskRun when all of the runs have been triggered asynchronously, and using the "parallel" processing strategy
processingJobsCount Int @default(0)
processingJobsExpectedCount Int @default(0)
/// optional token that can be used to authenticate the task run
oneTimeUseToken String?
// Run Engine v2 batch queue fields
/// When processing started (status changed to PROCESSING)
processingStartedAt DateTime?
/// When processing completed (all items processed)
processingCompletedAt DateTime?
/// Count of successfully created runs
successfulRunCount Int?
/// Count of failed run creations
failedRunCount Int?
/// Detailed failure records
errors BatchTaskRunError[]
///all the below properties are engine v1 only
items BatchTaskRunItem[]
taskIdentifier String?
checkpointEvent CheckpointRestoreEvent? @relation(fields: [checkpointEventId], references: [id], onDelete: Cascade, onUpdate: Cascade)
checkpointEventId String? @unique
dependentTaskAttempt TaskRunAttempt? @relation(fields: [dependentTaskAttemptId], references: [id], onDelete: Cascade, onUpdate: Cascade)
dependentTaskAttemptId String?
runDependencies TaskRunDependency[] @relation("dependentBatchRun")
@@unique([oneTimeUseToken])
///this is used for all engine versions
@@unique([runtimeEnvironmentId, idempotencyKey])
@@index([dependentTaskAttemptId])
// This is for the batch list dashboard page
@@index([runtimeEnvironmentId, id(sort: Desc)])
}
enum BatchTaskRunStatus {
PENDING
PROCESSING
COMPLETED
PARTIAL_FAILED
ABORTED
}
///Used in engine V1 only
///
/// Identical to the control-plane version: every relation stays within this
/// database and is kept as a real foreign key.
model BatchTaskRunItem {
id String @id @default(cuid())
status BatchTaskRunItemStatus @default(PENDING)
batchTaskRun BatchTaskRun @relation(fields: [batchTaskRunId], references: [id], onDelete: Cascade, onUpdate: Cascade)
batchTaskRunId String
taskRun TaskRun @relation(fields: [taskRunId], references: [id], onDelete: Cascade, onUpdate: Cascade)
taskRunId String
taskRunAttempt TaskRunAttempt? @relation(fields: [taskRunAttemptId], references: [id], onDelete: SetNull, onUpdate: Cascade)
taskRunAttemptId String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
completedAt DateTime?
@@unique([batchTaskRunId, taskRunId])
@@index([taskRunAttemptId], map: "idx_batchtaskrunitem_taskrunattempt")
@@index([taskRunId], map: "idx_batchtaskrunitem_taskrun")
}
enum BatchTaskRunItemStatus {
PENDING
FAILED
CANCELED
COMPLETED
}
/// Track individual run creation failures in batch processing (Run Engine v2)
///
/// Identical to the control-plane version: the batch relation stays within this
/// database and is kept as a real foreign key.
model BatchTaskRunError {
id String @id @default(cuid())
batchTaskRun BatchTaskRun @relation(fields: [batchTaskRunId], references: [id], onDelete: Cascade, onUpdate: Cascade)
batchTaskRunId String
/// Which item in the batch (0-based index)
index Int
/// The task identifier that was being triggered
taskIdentifier String
/// The payload that failed (JSON, may be truncated)
payload String?
/// The options that were used
options Json?
/// Error message
error String
/// Error code if available
errorCode String?
createdAt DateTime @default(now())
@@unique([batchTaskRunId, index])
@@index([batchTaskRunId])
}
/// Same columns and indexes as the control-plane version. The run and attempt
/// relations are kept as real foreign keys; the project and environment relations
/// are scalar-only foreign keys.
model Checkpoint {
id String @id @default(cuid())
friendlyId String @unique
type CheckpointType
location String
imageRef String
reason String?
metadata String?
events CheckpointRestoreEvent[]
run TaskRun @relation(fields: [runId], references: [id], onDelete: Cascade, onUpdate: Cascade)
runId String
attempt TaskRunAttempt @relation(fields: [attemptId], references: [id], onDelete: Cascade, onUpdate: Cascade)
attemptId String
attemptNumber Int?
/// scalar FK (control-plane `project` relation)
projectId String
/// scalar FK (control-plane `runtimeEnvironment` relation)
runtimeEnvironmentId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([attemptId])
@@index([runId])
}
enum CheckpointType {
DOCKER
KUBERNETES
}
/// Same columns and indexes as the control-plane version. The checkpoint, run,
/// and attempt relations are kept as real foreign keys; the project and
/// environment relations are scalar-only foreign keys.
model CheckpointRestoreEvent {
id String @id @default(cuid())
type CheckpointRestoreEventType
reason String?
metadata String?
checkpoint Checkpoint @relation(fields: [checkpointId], references: [id], onDelete: Cascade, onUpdate: Cascade)
checkpointId String
run TaskRun @relation(fields: [runId], references: [id], onDelete: Cascade, onUpdate: Cascade)
runId String
attempt TaskRunAttempt @relation(fields: [attemptId], references: [id], onDelete: Cascade, onUpdate: Cascade)
attemptId String
/// scalar FK (control-plane `project` relation)
projectId String
/// scalar FK (control-plane `runtimeEnvironment` relation)
runtimeEnvironmentId String
taskRunDependency TaskRunDependency?
batchTaskRunDependency BatchTaskRun?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([checkpointId])
@@index([runId])
}
enum CheckpointRestoreEventType {
CHECKPOINT
RESTORE
}
@@ -0,0 +1,72 @@
// Run Prisma migrations against the dedicated NEW run-ops database (the second physical DB in the
// split). It owns its own migration history, so it is migrated independently of the control-plane
// DB. Connects via RUN_OPS_DATABASE_URL — the same var the webapp uses — so migrations always
// target the DB the app connects to.
//
// Usage: node scripts/migrate.mjs [deploy|status] (defaults to deploy)
import { spawnSync } from "node:child_process";
import { readFileSync } from "node:fs";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
// Read from local .env files so dev works without an exported env; deploy environments inject vars directly.
function readFromEnvFiles(key) {
for (const file of [resolve(packageRoot, ".env"), resolve(packageRoot, "../../.env")]) {
let contents;
try {
contents = readFileSync(file, "utf8");
} catch {
continue;
}
for (const line of contents.split("\n")) {
const match = line.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*?)\s*$/);
if (!match || match[1] !== key) continue;
let value = match[2];
if (
(value.startsWith('"') && value.endsWith('"')) ||
(value.startsWith("'") && value.endsWith("'"))
) {
value = value.slice(1, -1);
}
if (value) return value;
}
}
return undefined;
}
// Expand `${VAR}` refs in env-file values (our manual reader loads them literally, unlike Prisma's
// dotenv-expand), so a `.env` like RUN_OPS_DATABASE_URL=${DATABASE_URL} still resolves.
const expand = (value) =>
value?.replace(/\$\{(\w+)\}/g, (_, k) => process.env[k] ?? readFromEnvFiles(k) ?? "");
const resolveVar = (key) => expand(process.env[key] || readFromEnvFiles(key));
const redact = (url) => url.replace(/:\/\/[^@]*@/, "://***@");
const subcommand = process.argv[2] === "status" ? "status" : "deploy";
const databaseUrl = resolveVar("RUN_OPS_DATABASE_URL");
if (!databaseUrl) {
// Single-DB installs never set it — safe no-op. A genuinely-expected DB is gated on by the caller.
console.log(
`run-ops migrate ${subcommand}: RUN_OPS_DATABASE_URL is not set (checked env and .env). ` +
"No dedicated run-ops database configured — skipping."
);
process.exit(0);
}
console.log(
`Running \`prisma migrate ${subcommand}\` against the run-ops database (${redact(databaseUrl)})`
);
const result = spawnSync("prisma", ["migrate", subcommand, "--schema", "prisma/schema.prisma"], {
cwd: packageRoot,
stdio: "inherit",
env: {
...process.env,
RUN_OPS_DATABASE_URL: databaseUrl,
},
});
process.exit(result.status ?? 1);
@@ -0,0 +1,4 @@
// The generated client class is named PrismaClient in BOTH packages; re-export it
// here under a distinct nominal alias so a consumer can import RunOpsPrismaClient
// and @trigger.dev/database's PrismaClient in the same module without a clash.
export { PrismaClient as RunOpsPrismaClient } from "../generated/run-ops/index.js";
@@ -0,0 +1,13 @@
{
"compilerOptions": {
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"moduleResolution": "node",
"preserveWatchOutput": true,
"skipLibCheck": true,
"noEmit": true,
"strict": true
},
"exclude": ["node_modules", "dist", "generated", "**/*.test.ts", "vitest.config.ts"]
}
@@ -0,0 +1,10 @@
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
include: ["**/*.test.ts"],
globals: true,
isolate: true,
testTimeout: 10_000,
},
});