Skip to content

Commit 471d94c

Browse files
committed
fix(webapp): re-sync engine limits when an override lands during a deploy
The optimistic markers only guard the Postgres write; an override or reset landing between that write and the engine sync would leave the engine holding the deploy's stale values. The deploy now re-reads the markers after syncing and re-syncs once from the fresh row when they moved, so the last engine write always carries the freshest limits.
1 parent 655af87 commit 471d94c

1 file changed

Lines changed: 58 additions & 34 deletions

File tree

‎apps/webapp/app/v3/services/createBackgroundWorker.server.ts‎

Lines changed: 58 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -771,53 +771,77 @@ async function createWorkerQueue(
771771
concurrencyVersion
772772
);
773773

774-
const newConcurrencyLimit = taskQueue.concurrencyLimit;
775-
776-
/**
777-
* The total limit key is separate from the per-queue limit key that pause zeroes,
778-
* so it is safe to sync it regardless of the paused state. The engine clamps it
779-
* to the environment limit at read time, so the raw declared value is stored.
780-
*/
781-
if (typeof taskQueue.totalConcurrencyLimit === "number") {
782-
await updateQueueTotalConcurrencyLimits(
783-
environment,
784-
taskQueue.name,
785-
taskQueue.totalConcurrencyLimit
786-
);
787-
} else {
788-
await removeQueueTotalConcurrencyLimits(environment, taskQueue.name);
789-
}
774+
const syncQueueLimitsToEngine = async (row: {
775+
name: string;
776+
paused: boolean;
777+
concurrencyLimit: number | null;
778+
totalConcurrencyLimit: number | null;
779+
}) => {
780+
/**
781+
* The total limit key is separate from the per-queue limit key that pause zeroes,
782+
* so it is safe to sync it regardless of the paused state. The engine clamps it
783+
* to the environment limit at read time, so the raw declared value is stored.
784+
*/
785+
if (typeof row.totalConcurrencyLimit === "number") {
786+
await updateQueueTotalConcurrencyLimits(environment, row.name, row.totalConcurrencyLimit);
787+
} else {
788+
await removeQueueTotalConcurrencyLimits(environment, row.name);
789+
}
790790

791-
if (!taskQueue.paused) {
792-
if (typeof newConcurrencyLimit === "number") {
793-
logger.debug("createWorkerQueue: updating concurrency limit", {
791+
if (!row.paused) {
792+
logger.debug("createWorkerQueue: syncing concurrency limit", {
794793
workerId: worker.id,
795-
taskQueue,
794+
taskQueue: row,
796795
orgId: environment.organizationId,
797796
projectId: environment.projectId,
798797
environmentId: environment.id,
799-
concurrencyLimit: newConcurrencyLimit,
798+
concurrencyLimit: row.concurrencyLimit,
800799
});
801-
await updateQueueConcurrencyLimits(environment, taskQueue.name, newConcurrencyLimit);
800+
if (typeof row.concurrencyLimit === "number") {
801+
await updateQueueConcurrencyLimits(environment, row.name, row.concurrencyLimit);
802+
} else {
803+
await removeQueueConcurrencyLimits(environment, row.name);
804+
}
802805
} else {
803-
logger.debug("createWorkerQueue: removing concurrency limit", {
806+
logger.debug("createWorkerQueue: queue is paused, not updating concurrency limit", {
804807
workerId: worker.id,
805-
taskQueue,
808+
taskQueue: row,
806809
orgId: environment.organizationId,
807810
projectId: environment.projectId,
808811
environmentId: environment.id,
809-
concurrencyLimit: newConcurrencyLimit,
810812
});
811-
await removeQueueConcurrencyLimits(environment, taskQueue.name);
812813
}
813-
} else {
814-
logger.debug("createWorkerQueue: queue is paused, not updating concurrency limit", {
815-
workerId: worker.id,
816-
taskQueue,
817-
orgId: environment.organizationId,
818-
projectId: environment.projectId,
819-
environmentId: environment.id,
820-
});
814+
};
815+
816+
await syncQueueLimitsToEngine(taskQueue);
817+
818+
/**
819+
* The optimistic markers only guard the Postgres write; an override or reset can
820+
* still land between that write and the engine sync above, which would leave the
821+
* engine holding this deploy's stale values. Re-read the markers and re-sync once
822+
* from the fresh row when they moved: every actor writes Postgres before its own
823+
* engine sync, so whoever syncs last is syncing the freshest row.
824+
*/
825+
const freshQueue = await prisma.taskQueue.findFirst({
826+
where: { id: taskQueue.id },
827+
select: {
828+
name: true,
829+
paused: true,
830+
concurrencyLimit: true,
831+
totalConcurrencyLimit: true,
832+
concurrencyLimitOverriddenAt: true,
833+
totalConcurrencyLimitOverriddenAt: true,
834+
},
835+
});
836+
837+
if (
838+
freshQueue &&
839+
(freshQueue.concurrencyLimitOverriddenAt?.getTime() !==
840+
taskQueue.concurrencyLimitOverriddenAt?.getTime() ||
841+
freshQueue.totalConcurrencyLimitOverriddenAt?.getTime() !==
842+
taskQueue.totalConcurrencyLimitOverriddenAt?.getTime())
843+
) {
844+
await syncQueueLimitsToEngine(freshQueue);
821845
}
822846

823847
return taskQueue;

0 commit comments

Comments
 (0)