feat(pipeline): render queue, worker service and automated preview generation
One "Queue Export" click now renders the EXR sequence, then rebuilds the shot headlessly with the studio slate/overlay template to produce the delivery MOV and review MP4. Implements RenderPipeline2 phases 1-2 plus the preview stage. Server: - New models Export, RenderJob, ExportEvent, Machine, WorkerHeartbeat, plus Project.deliveryConfig and per-submission slate fields (Export.vfxScope, Export.submissionNote, inherited from the shot's previous export). Both migrations are purely additive; no existing column is touched. - lib/render-pipeline: server-enforced state machine, transactional version increment with supersede, atomic FOR UPDATE SKIP LOCKED claim gated by machine availability windows, and a lease reaper run from instrumentation.ts. - /api/ext/* endpoints for the panel and workers; session-auth mirrors under /api/render and /api/machines for the web UI. - Pipeline pages: render queue, export detail, machine monitoring, plus an Exports tab on shot detail. RenderWorker (.NET 8 Windows service, new): - Registration, heartbeat as cancel channel, claim loop, aerender runner with progress parsing and stall watchdog, crash recovery and disk-spooled reporting that survives server downtime. - Preview stage: headless AE assembles the preview comp into a throwaway AEP with both output modules queued, then a single aerender pass renders them. Preview jobs are not claimed while an interactive AE session is open, so an artist's project is never taken over. AE panel: Queue Export with live status polling, urgent flag, retry, and the VFX Scope / Submission Note fields. Every existing panel action is unchanged. Preview chaining ships disabled behind SystemConfig preview.enabled. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,178 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "ExportStatus" AS ENUM ('QUEUED', 'RENDERING', 'RENDER_FAILED', 'VALIDATING', 'VALIDATION_FAILED', 'GENERATING_PREVIEW', 'PREVIEW_FAILED', 'READY_FOR_QC', 'QC_FAILED', 'READY_FOR_DELIVERY', 'PACKAGED', 'DELIVERED', 'SUPERSEDED', 'ARCHIVED', 'CANCELLED');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "RenderJobStatus" AS ENUM ('QUEUED', 'CLAIMED', 'RUNNING', 'COMPLETED', 'FAILED', 'CANCELLED', 'EXPIRED');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "RenderJobType" AS ENUM ('AE_RENDER', 'PREVIEW_ONLY', 'DELIVERY_BUILD');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "ValidationStatus" AS ENUM ('PASS', 'FAIL', 'WARN', 'SKIPPED');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "QCResult" AS ENUM ('PASS', 'FAIL');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "MachineStatus" AS ENUM ('ONLINE', 'OFFLINE', 'DISABLED');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "DeliveryStatus" AS ENUM ('DRAFT', 'QUEUED', 'BUILDING', 'READY', 'DELIVERED', 'FAILED', 'CANCELLED');
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "projects" ADD COLUMN "deliveryConfig" JSONB;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "exports" (
|
||||
"id" TEXT NOT NULL,
|
||||
"shotId" TEXT NOT NULL,
|
||||
"projectId" TEXT NOT NULL,
|
||||
"taskId" TEXT,
|
||||
"versionId" TEXT,
|
||||
"versionNumber" INTEGER NOT NULL,
|
||||
"versionString" TEXT NOT NULL,
|
||||
"status" "ExportStatus" NOT NULL DEFAULT 'QUEUED',
|
||||
"statusChangedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"aepPath" TEXT NOT NULL,
|
||||
"compName" TEXT NOT NULL,
|
||||
"rendererType" TEXT NOT NULL,
|
||||
"outputDir" TEXT NOT NULL,
|
||||
"outputPattern" TEXT NOT NULL,
|
||||
"frameStart" INTEGER NOT NULL,
|
||||
"frameEnd" INTEGER NOT NULL,
|
||||
"fps" DOUBLE PRECISION NOT NULL,
|
||||
"width" INTEGER NOT NULL,
|
||||
"height" INTEGER NOT NULL,
|
||||
"colorspace" TEXT,
|
||||
"deliveryMovPath" TEXT,
|
||||
"previewMovKey" TEXT,
|
||||
"thumbnailKey" TEXT,
|
||||
"metadataKey" TEXT,
|
||||
"exrFileCount" INTEGER,
|
||||
"exrTotalBytes" BIGINT,
|
||||
"checksum" TEXT,
|
||||
"submittedById" TEXT,
|
||||
"submittedByName" TEXT,
|
||||
"supersededById" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "exports_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "render_jobs" (
|
||||
"id" TEXT NOT NULL,
|
||||
"type" "RenderJobType" NOT NULL DEFAULT 'AE_RENDER',
|
||||
"exportId" TEXT,
|
||||
"deliveryId" TEXT,
|
||||
"attempt" INTEGER NOT NULL DEFAULT 1,
|
||||
"maxAttempts" INTEGER NOT NULL DEFAULT 3,
|
||||
"status" "RenderJobStatus" NOT NULL DEFAULT 'QUEUED',
|
||||
"priority" INTEGER NOT NULL DEFAULT 50,
|
||||
"manifest" JSONB NOT NULL,
|
||||
"machineId" TEXT,
|
||||
"claimedAt" TIMESTAMP(3),
|
||||
"leaseExpiresAt" TIMESTAMP(3),
|
||||
"startedAt" TIMESTAMP(3),
|
||||
"finishedAt" TIMESTAMP(3),
|
||||
"progress" DOUBLE PRECISION NOT NULL DEFAULT 0,
|
||||
"currentFrame" INTEGER,
|
||||
"totalFrames" INTEGER,
|
||||
"etaSeconds" INTEGER,
|
||||
"exitCode" INTEGER,
|
||||
"errorMessage" TEXT,
|
||||
"logTail" TEXT,
|
||||
"logFileKey" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "render_jobs_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "export_events" (
|
||||
"id" TEXT NOT NULL,
|
||||
"exportId" TEXT NOT NULL,
|
||||
"fromStatus" TEXT,
|
||||
"toStatus" TEXT NOT NULL,
|
||||
"actorType" TEXT NOT NULL,
|
||||
"actorId" TEXT,
|
||||
"note" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "export_events_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "machines" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"hostname" TEXT NOT NULL,
|
||||
"status" "MachineStatus" NOT NULL DEFAULT 'OFFLINE',
|
||||
"enabled" BOOLEAN NOT NULL DEFAULT true,
|
||||
"lastSeenAt" TIMESTAMP(3),
|
||||
"workerVersion" TEXT,
|
||||
"aeVersion" TEXT,
|
||||
"capabilities" JSONB,
|
||||
"availability" JSONB,
|
||||
"renderNowUntil" TIMESTAMP(3),
|
||||
"apiKeyHash" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "machines_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "worker_heartbeats" (
|
||||
"id" TEXT NOT NULL,
|
||||
"machineId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"cpuPercent" DOUBLE PRECISION,
|
||||
"memPercent" DOUBLE PRECISION,
|
||||
"diskFreeGb" DOUBLE PRECISION,
|
||||
"currentJobId" TEXT,
|
||||
|
||||
CONSTRAINT "worker_heartbeats_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "exports_status_idx" ON "exports"("status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "exports_projectId_status_idx" ON "exports"("projectId", "status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "exports_shotId_versionNumber_key" ON "exports"("shotId", "versionNumber");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "render_jobs_status_priority_createdAt_idx" ON "render_jobs"("status", "priority", "createdAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "render_jobs_machineId_status_idx" ON "render_jobs"("machineId", "status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "export_events_exportId_createdAt_idx" ON "export_events"("exportId", "createdAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "machines_name_key" ON "machines"("name");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "worker_heartbeats_machineId_createdAt_idx" ON "worker_heartbeats"("machineId", "createdAt");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "exports" ADD CONSTRAINT "exports_shotId_fkey" FOREIGN KEY ("shotId") REFERENCES "shots"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "render_jobs" ADD CONSTRAINT "render_jobs_exportId_fkey" FOREIGN KEY ("exportId") REFERENCES "exports"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "render_jobs" ADD CONSTRAINT "render_jobs_machineId_fkey" FOREIGN KEY ("machineId") REFERENCES "machines"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "export_events" ADD CONSTRAINT "export_events_exportId_fkey" FOREIGN KEY ("exportId") REFERENCES "exports"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "worker_heartbeats" ADD CONSTRAINT "worker_heartbeats_machineId_fkey" FOREIGN KEY ("machineId") REFERENCES "machines"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
Reference in New Issue
Block a user