diff --git a/.server-changes/strip-background-worker-metadata.md b/.server-changes/strip-background-worker-metadata.md new file mode 100644 index 0000000000..c92ee62b1d --- /dev/null +++ b/.server-changes/strip-background-worker-metadata.md @@ -0,0 +1,6 @@ +--- +area: webapp +type: improvement +--- + +Strip BackgroundWorker.metadata to the schedule slice read at deploy promotion, removing a 5+ second event-loop block in Prisma's client serializer when creating workers for projects with many tasks or source files. diff --git a/apps/webapp/app/v3/services/createBackgroundWorker.server.ts b/apps/webapp/app/v3/services/createBackgroundWorker.server.ts index c838132724..459686ed97 100644 --- a/apps/webapp/app/v3/services/createBackgroundWorker.server.ts +++ b/apps/webapp/app/v3/services/createBackgroundWorker.server.ts @@ -29,6 +29,32 @@ import { tryCatch } from "@trigger.dev/core/v3"; import { engine } from "../runEngine.server"; import { scheduleEngine } from "../scheduleEngine.server"; +/** + * Strip BackgroundWorkerMetadata down to the slice that's actually read after + * storage. Everything else is duplicated to dedicated columns/tables + * (BackgroundWorker.{contentHash,cliVersion,sdkVersion,runtime,runtimeVersion}, + * BackgroundWorkerTask, BackgroundWorkerFile, TaskQueue, Prompt). Today the + * only post-write reader is changeCurrentDeployment.server.ts, which feeds + * tasks[].schedule into syncDeclarativeSchedules. packageVersion, contentHash, + * and tasks[].filePath are kept solely to satisfy BackgroundWorkerMetadata's + * required fields when the column is parsed back. + */ +export function stripBackgroundWorkerMetadataForStorage( + metadata: BackgroundWorkerMetadata +): Prisma.InputJsonValue { + return { + packageVersion: metadata.packageVersion, + contentHash: metadata.contentHash, + tasks: metadata.tasks + .filter((t) => t.schedule) + .map((t) => ({ + id: t.id, + filePath: t.filePath, + schedule: t.schedule, + })), + }; +} + export class CreateBackgroundWorkerService extends BaseService { public async call( projectRef: string, @@ -79,8 +105,7 @@ export class CreateBackgroundWorkerService extends BaseService { version: nextVersion, runtimeEnvironmentId: environment.id, projectId: project.id, - // body.metadata has an index signature that Prisma doesn't like (from the JSONSchema type) so we are safe to just cast it - metadata: body.metadata as Prisma.InputJsonValue, + metadata: stripBackgroundWorkerMetadataForStorage(body.metadata), contentHash: body.metadata.contentHash, cliVersion: body.metadata.cliPackageVersion, sdkVersion: body.metadata.packageVersion, diff --git a/apps/webapp/app/v3/services/createDeploymentBackgroundWorkerV3.server.ts b/apps/webapp/app/v3/services/createDeploymentBackgroundWorkerV3.server.ts index 9743cffcdb..f20a024d2d 100644 --- a/apps/webapp/app/v3/services/createDeploymentBackgroundWorkerV3.server.ts +++ b/apps/webapp/app/v3/services/createDeploymentBackgroundWorkerV3.server.ts @@ -1,5 +1,5 @@ import { CreateBackgroundWorkerRequestBody, tryCatch } from "@trigger.dev/core/v3"; -import type { BackgroundWorker, Prisma } from "@trigger.dev/database"; +import type { BackgroundWorker } from "@trigger.dev/database"; import { AuthenticatedEnvironment } from "~/services/apiAuth.server"; import { logger } from "~/services/logger.server"; import { syncTaskIdentifiers } from "~/services/taskIdentifierRegistry.server"; @@ -7,7 +7,11 @@ import { socketIo } from "../handleSocketIo.server"; import { updateEnvConcurrencyLimits } from "../runQueue.server"; import { PerformDeploymentAlertsService } from "./alerts/performDeploymentAlerts.server"; import { BaseService } from "./baseService.server"; -import { createWorkerResources, syncDeclarativeSchedules } from "./createBackgroundWorker.server"; +import { + createWorkerResources, + stripBackgroundWorkerMetadataForStorage, + syncDeclarativeSchedules, +} from "./createBackgroundWorker.server"; import { ExecuteTasksWaitingForDeployService } from "./executeTasksWaitingForDeploy"; import { projectPubSub } from "./projectPubSub.server"; import { TimeoutDeploymentService } from "./timeoutDeployment.server"; @@ -49,8 +53,7 @@ export class CreateDeploymentBackgroundWorkerServiceV3 extends BaseService { version: deployment.version, runtimeEnvironmentId: environment.id, projectId: environment.projectId, - // body.metadata has an index signature that Prisma doesn't like (from the JSONSchema type) so we are safe to just cast it - metadata: body.metadata as Prisma.InputJsonValue, + metadata: stripBackgroundWorkerMetadataForStorage(body.metadata), contentHash: body.metadata.contentHash, cliVersion: body.metadata.cliPackageVersion, sdkVersion: body.metadata.packageVersion, diff --git a/apps/webapp/app/v3/services/createDeploymentBackgroundWorkerV4.server.ts b/apps/webapp/app/v3/services/createDeploymentBackgroundWorkerV4.server.ts index cc73a8569d..67269c88d8 100644 --- a/apps/webapp/app/v3/services/createDeploymentBackgroundWorkerV4.server.ts +++ b/apps/webapp/app/v3/services/createDeploymentBackgroundWorkerV4.server.ts @@ -1,11 +1,12 @@ import { CreateBackgroundWorkerRequestBody, logger, tryCatch } from "@trigger.dev/core/v3"; import { BackgroundWorkerId } from "@trigger.dev/core/v3/isomorphic"; -import type { BackgroundWorker, Prisma, WorkerDeployment } from "@trigger.dev/database"; +import type { BackgroundWorker, WorkerDeployment } from "@trigger.dev/database"; import { AuthenticatedEnvironment } from "~/services/apiAuth.server"; import { BaseService, ServiceValidationError } from "./baseService.server"; import { createBackgroundFiles, createWorkerResources, + stripBackgroundWorkerMetadataForStorage, syncDeclarativeSchedules, } from "./createBackgroundWorker.server"; import { TimeoutDeploymentService } from "./timeoutDeployment.server"; @@ -65,8 +66,7 @@ export class CreateDeploymentBackgroundWorkerServiceV4 extends BaseService { version: deployment.version, runtimeEnvironmentId: environment.id, projectId: environment.projectId, - // body.metadata has an index signature that Prisma doesn't like (from the JSONSchema type) so we are safe to just cast it - metadata: body.metadata as Prisma.InputJsonValue, + metadata: stripBackgroundWorkerMetadataForStorage(body.metadata), contentHash: body.metadata.contentHash, cliVersion: body.metadata.cliPackageVersion, sdkVersion: body.metadata.packageVersion,