Skip to content

Commit 30bd567

Browse files
fix: sync declarative schedules on deployment rollback (#3468)
## ✅ Checklist - [x] I have followed every step in the [contributing guide](https://github.com/triggerdotdev/trigger.dev/blob/main/CONTRIBUTING.md) - [x] The PR title follows the convention. - [x] I ran and tested the code works --- ## Testing - Reviewed the code flow for deployment rollback (`ChangeCurrentDeploymentService`) and confirmed it was missing schedule sync - Verified all 4 callers of `ChangeCurrentDeploymentService` (UI rollback, UI promote, API promote, finalize deployment) are now covered - Ran `pnpm run typecheck --filter webapp` — passes cleanly --- ## Changelog When rolling back (or manually promoting) a deployment, declarative schedules were not being synced to match the target deployment's worker metadata. Schedules remained as configured by the most recent deployment rather than reflecting the target version's schedule configuration. This fix adds a call to `syncDeclarativeSchedules` in `ChangeCurrentDeploymentService` after the deployment promotion is updated. It parses the target deployment's stored `BackgroundWorkerMetadata` to restore the correct schedule state. This covers both rollback and promote paths (UI and API). Errors are handled gracefully so they don't block the deployment change itself. --- ## Screenshots N/A — backend-only change. 💯 Link to Devin session: https://app.devin.ai/sessions/0debf012b58c4132be778f8ea88cd2b6 --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: nick <55853254+nicktrn@users.noreply.github.com>
1 parent 139cccf commit 30bd567

2 files changed

Lines changed: 64 additions & 9 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
area: webapp
3+
type: fix
4+
---
5+
6+
Sync declarative schedules when rolling back or promoting deployments

apps/webapp/app/v3/services/changeCurrentDeployment.server.ts

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { tryCatch } from "@trigger.dev/core/v3";
1+
import { BackgroundWorkerMetadata, tryCatch } from "@trigger.dev/core/v3";
22
import { CURRENT_DEPLOYMENT_LABEL } from "@trigger.dev/core/v3/isomorphic";
33
import { WorkerDeployment } from "@trigger.dev/database";
44
import { logger } from "~/services/logger.server";
55
import { syncTaskIdentifiers } from "~/services/taskIdentifierRegistry.server";
66
import { BaseService, ServiceValidationError } from "./baseService.server";
7+
import { syncDeclarativeSchedules } from "./createBackgroundWorker.server";
78
import { ExecuteTasksWaitingForDeployService } from "./executeTasksWaitingForDeploy";
89
import { compareDeploymentVersions } from "../utils/deploymentVersions";
910

@@ -53,10 +54,8 @@ export class ChangeCurrentDeploymentService extends BaseService {
5354
switch (direction) {
5455
case "promote": {
5556
if (
56-
compareDeploymentVersions(
57-
currentPromotion.deployment.version,
58-
deployment.version
59-
) >= 0
57+
compareDeploymentVersions(currentPromotion.deployment.version, deployment.version) >=
58+
0
6059
) {
6160
throw new ServiceValidationError(
6261
"Cannot promote a deployment that is older than the current deployment."
@@ -66,10 +65,8 @@ export class ChangeCurrentDeploymentService extends BaseService {
6665
}
6766
case "rollback": {
6867
if (
69-
compareDeploymentVersions(
70-
currentPromotion.deployment.version,
71-
deployment.version
72-
) <= 0
68+
compareDeploymentVersions(currentPromotion.deployment.version, deployment.version) <=
69+
0
7370
) {
7471
throw new ServiceValidationError(
7572
"Cannot rollback to a deployment that is newer than the current deployment."
@@ -118,6 +115,58 @@ export class ChangeCurrentDeploymentService extends BaseService {
118115
logger.error("Error syncing task identifiers on deployment change", { error: syncError });
119116
}
120117

118+
const [scheduleSyncError] = await tryCatch(this.#syncSchedulesForDeployment(deployment));
119+
120+
if (scheduleSyncError) {
121+
logger.error("Error syncing declarative schedules on deployment change", {
122+
error: scheduleSyncError,
123+
});
124+
}
125+
121126
await ExecuteTasksWaitingForDeployService.enqueue(deployment.workerId);
122127
}
128+
129+
async #syncSchedulesForDeployment(deployment: WorkerDeployment) {
130+
const worker = await this._prisma.backgroundWorker.findFirst({
131+
where: { id: deployment.workerId! },
132+
});
133+
134+
if (!worker) {
135+
logger.error("Worker not found for deployment schedule sync", {
136+
deploymentId: deployment.id,
137+
workerId: deployment.workerId,
138+
});
139+
return;
140+
}
141+
142+
const parsed = BackgroundWorkerMetadata.safeParse(worker.metadata);
143+
144+
if (!parsed.success) {
145+
logger.error("Failed to parse worker metadata for schedule sync", {
146+
deploymentId: deployment.id,
147+
workerId: deployment.workerId,
148+
error: parsed.error,
149+
});
150+
return;
151+
}
152+
153+
const environment = await this._prisma.runtimeEnvironment.findFirst({
154+
where: { id: deployment.environmentId },
155+
include: {
156+
project: true,
157+
organization: true,
158+
orgMember: true,
159+
},
160+
});
161+
162+
if (!environment) {
163+
logger.error("Environment not found for deployment schedule sync", {
164+
deploymentId: deployment.id,
165+
environmentId: deployment.environmentId,
166+
});
167+
return;
168+
}
169+
170+
await syncDeclarativeSchedules(parsed.data.tasks, worker, environment, this._prisma);
171+
}
123172
}

0 commit comments

Comments
 (0)