Skip to content

Commit 251e46f

Browse files
committed
fix: wrap prompt version label removal + creation in transaction to prevent orphaned labels on concurrent deploy
1 parent 543bf2c commit 251e46f

File tree

1 file changed

+31
-27
lines changed

1 file changed

+31
-27
lines changed

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

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -780,40 +780,44 @@ async function createWorkerPrompts(
780780

781781
const nextVersion = (latestVersion?.version ?? 0) + 1;
782782

783-
// Remove "latest" label from all existing versions
784-
if (latestVersion) {
785-
await prisma.$executeRaw`
786-
UPDATE "prompt_versions"
787-
SET "labels" = array_remove("labels", 'latest')
788-
WHERE "promptId" = ${prompt.id} AND 'latest' = ANY("labels")
789-
`;
790-
}
791-
792783
// Determine labels for the new version.
793784
// Deploys always move "current" to the new code version. If a dashboard
794785
// override exists, it sits on top via the "override" label and the API
795786
// serves that instead — so "current" movement is safe.
796787
const labels = ["latest", "current"];
797788

798-
// Remove "current" from any existing version
799-
await prisma.$executeRaw`
800-
UPDATE "prompt_versions"
801-
SET "labels" = array_remove("labels", 'current')
802-
WHERE "promptId" = ${prompt.id} AND 'current' = ANY("labels")
803-
`;
789+
// Wrap label removal + version creation in a transaction so labels
790+
// aren't stripped if the create fails (e.g. concurrent deploy race).
791+
await prisma.$transaction(async (tx) => {
792+
// Remove "latest" label from all existing versions
793+
if (latestVersion) {
794+
await tx.$executeRaw`
795+
UPDATE "prompt_versions"
796+
SET "labels" = array_remove("labels", 'latest')
797+
WHERE "promptId" = ${prompt.id} AND 'latest' = ANY("labels")
798+
`;
799+
}
804800

805-
await prisma.promptVersion.create({
806-
data: {
807-
promptId: prompt.id,
808-
version: nextVersion,
809-
textContent: contentString,
810-
model: promptResource.model,
811-
config: promptResource.config as any,
812-
source: "code",
813-
contentHash,
814-
labels,
815-
workerId: worker.id,
816-
},
801+
// Remove "current" from any existing version
802+
await tx.$executeRaw`
803+
UPDATE "prompt_versions"
804+
SET "labels" = array_remove("labels", 'current')
805+
WHERE "promptId" = ${prompt.id} AND 'current' = ANY("labels")
806+
`;
807+
808+
await tx.promptVersion.create({
809+
data: {
810+
promptId: prompt.id,
811+
version: nextVersion,
812+
textContent: contentString,
813+
model: promptResource.model,
814+
config: promptResource.config as any,
815+
source: "code",
816+
contentHash,
817+
labels,
818+
workerId: worker.id,
819+
},
820+
});
817821
});
818822

819823
logger.debug("Registered prompt version", {

0 commit comments

Comments
 (0)