perf(webapp): trim BackgroundWorker.metadata to the schedule slice on create (#3525)
Large deploys (projects with many tasks or source files) blocked the
webapp event loop for several seconds inside Prisma's client-side
serializer on `BackgroundWorker.create`, tail-latencying every other
in-flight request on the same Node process. The `metadata` JSON column
was being written with the full deploy manifest — every task's config,
every queue and prompt, and the full source of every file — all of which
already live on dedicated columns or in dedicated tables.
Fix: project the manifest to `{ packageVersion, contentHash, tasks: [{
id, filePath, schedule }] }` on insert. The only post-write read site is
`changeCurrentDeployment`, which feeds `tasks[].schedule` into
`syncDeclarativeSchedules` at deploy promotion. The retained top-level
keys and per-task `filePath` are kept solely so
`BackgroundWorkerMetadata.safeParse` still succeeds on read.
## Test plan
- [ ] Deploy a project with declarative schedules; verify schedules are
created on first deploy
- [ ] Modify / remove schedules across subsequent deploys; verify sync
- [ ] Roll back to a previous deploy; verify `changeCurrentDeployment`
re-syncs schedules
- [ ] Inspect `BackgroundWorker.metadata` on a fresh deploy — should be
a small object, not the full manifest
This commit is contained in:
@@ -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.
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user