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>
This commit is contained in:
committed by
GitHub
parent
139cccf27e
commit
30bd567d48
@@ -0,0 +1,6 @@
|
||||
---
|
||||
area: webapp
|
||||
type: fix
|
||||
---
|
||||
|
||||
Sync declarative schedules when rolling back or promoting deployments
|
||||
@@ -1,9 +1,10 @@
|
||||
import { tryCatch } from "@trigger.dev/core/v3";
|
||||
import { BackgroundWorkerMetadata, tryCatch } from "@trigger.dev/core/v3";
|
||||
import { CURRENT_DEPLOYMENT_LABEL } from "@trigger.dev/core/v3/isomorphic";
|
||||
import { WorkerDeployment } from "@trigger.dev/database";
|
||||
import { logger } from "~/services/logger.server";
|
||||
import { syncTaskIdentifiers } from "~/services/taskIdentifierRegistry.server";
|
||||
import { BaseService, ServiceValidationError } from "./baseService.server";
|
||||
import { syncDeclarativeSchedules } from "./createBackgroundWorker.server";
|
||||
import { ExecuteTasksWaitingForDeployService } from "./executeTasksWaitingForDeploy";
|
||||
import { compareDeploymentVersions } from "../utils/deploymentVersions";
|
||||
|
||||
@@ -53,10 +54,8 @@ export class ChangeCurrentDeploymentService extends BaseService {
|
||||
switch (direction) {
|
||||
case "promote": {
|
||||
if (
|
||||
compareDeploymentVersions(
|
||||
currentPromotion.deployment.version,
|
||||
deployment.version
|
||||
) >= 0
|
||||
compareDeploymentVersions(currentPromotion.deployment.version, deployment.version) >=
|
||||
0
|
||||
) {
|
||||
throw new ServiceValidationError(
|
||||
"Cannot promote a deployment that is older than the current deployment."
|
||||
@@ -66,10 +65,8 @@ export class ChangeCurrentDeploymentService extends BaseService {
|
||||
}
|
||||
case "rollback": {
|
||||
if (
|
||||
compareDeploymentVersions(
|
||||
currentPromotion.deployment.version,
|
||||
deployment.version
|
||||
) <= 0
|
||||
compareDeploymentVersions(currentPromotion.deployment.version, deployment.version) <=
|
||||
0
|
||||
) {
|
||||
throw new ServiceValidationError(
|
||||
"Cannot rollback to a deployment that is newer than the current deployment."
|
||||
@@ -118,6 +115,58 @@ export class ChangeCurrentDeploymentService extends BaseService {
|
||||
logger.error("Error syncing task identifiers on deployment change", { error: syncError });
|
||||
}
|
||||
|
||||
const [scheduleSyncError] = await tryCatch(this.#syncSchedulesForDeployment(deployment));
|
||||
|
||||
if (scheduleSyncError) {
|
||||
logger.error("Error syncing declarative schedules on deployment change", {
|
||||
error: scheduleSyncError,
|
||||
});
|
||||
}
|
||||
|
||||
await ExecuteTasksWaitingForDeployService.enqueue(deployment.workerId);
|
||||
}
|
||||
|
||||
async #syncSchedulesForDeployment(deployment: WorkerDeployment) {
|
||||
const worker = await this._prisma.backgroundWorker.findFirst({
|
||||
where: { id: deployment.workerId! },
|
||||
});
|
||||
|
||||
if (!worker) {
|
||||
logger.error("Worker not found for deployment schedule sync", {
|
||||
deploymentId: deployment.id,
|
||||
workerId: deployment.workerId,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const parsed = BackgroundWorkerMetadata.safeParse(worker.metadata);
|
||||
|
||||
if (!parsed.success) {
|
||||
logger.error("Failed to parse worker metadata for schedule sync", {
|
||||
deploymentId: deployment.id,
|
||||
workerId: deployment.workerId,
|
||||
error: parsed.error,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const environment = await this._prisma.runtimeEnvironment.findFirst({
|
||||
where: { id: deployment.environmentId },
|
||||
include: {
|
||||
project: true,
|
||||
organization: true,
|
||||
orgMember: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!environment) {
|
||||
logger.error("Environment not found for deployment schedule sync", {
|
||||
deploymentId: deployment.id,
|
||||
environmentId: deployment.environmentId,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await syncDeclarativeSchedules(parsed.data.tasks, worker, environment, this._prisma);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user