mirror of
https://github.com/webstudio-is/webstudio.git
synced 2026-11-09 14:03:33 +09:00
Merge branch 'main' into 252-fonts-manager-and-fonts-selector-font-upload
This commit is contained in:
6 files changed
+146
-85
No files matched your search
@@ -0,0 +1,46 @@
|
||||
## A migration failed in PREVIEW, how do I fix the PREVIEW database
|
||||
|
||||
1. Open a new PR where you'll do the fix
|
||||
1. Go to https://vercel.com/webstudio-is/webstudio-designer/settings/environment-variables
|
||||
1. Set APPLY_MIGRATIONS to "true" for your PR's branch
|
||||
1. Fix the failed migration code
|
||||
1. Fix the database mannually if the migration have been applied half-way
|
||||
1. Temporarily change `ci:migrate` script to run `resolve` before applying migrations: `"ci:migrate": "migrations resolve rolled-back <name> --force && migrations migrate --force"`. Use `applied` instead of `rolled-back` if you manually applied the migration at previous step.
|
||||
1. Commit the changes and check Vercel logs to see if the migration is applied
|
||||
1. Change `ci:migrate` script back to normal
|
||||
1. Merge the PR
|
||||
1. Remove APPLY_MIGRATIONS from Vercel settings for your branch
|
||||
|
||||
## Transacation failed with a error "Transaction API error: Transaction already closed: Could not perform operation."
|
||||
|
||||
Most likely reason Prisma has thrown this error is because transaction has timed out.
|
||||
If that's the case, you have the following options:
|
||||
|
||||
1. Optimize your migration to make it faster
|
||||
2. Increase the timeout:
|
||||
|
||||
```js
|
||||
export default () => {
|
||||
const client = new PrismaClient();
|
||||
return client.$transaction(
|
||||
async (prisma) => {
|
||||
// migration code...
|
||||
},
|
||||
{
|
||||
timeout: 1000 * 60 * 2, // in milliseconds, default 5000
|
||||
}
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
3. Do not wrap the migration body into a transaction:
|
||||
|
||||
```js
|
||||
export default async () => {
|
||||
const prisma = new PrismaClient();
|
||||
// use `prisma` here without wrapping it into a transaction
|
||||
};
|
||||
```
|
||||
|
||||
Note that in this case if the migration fails again, it will be harder to fix the database,
|
||||
because the migration can end up half-way applied.
|
||||
@@ -2,6 +2,7 @@ import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { FileLocker, MigrationMeta } from "umzug";
|
||||
import confirm from "@inquirer/confirm";
|
||||
import { inspect } from "node:util";
|
||||
import * as prismaMigrations from "./prisma-migrations";
|
||||
import { umzug } from "./umzug";
|
||||
import * as logger from "./logger";
|
||||
@@ -256,13 +257,18 @@ If you're sure no other process is running, please delete the lockfile:
|
||||
try {
|
||||
await umzug.up();
|
||||
} catch (err) {
|
||||
const originalError: unknown = err.cause || err;
|
||||
const originalErrorString =
|
||||
(originalError instanceof Error && originalError.stack) ||
|
||||
inspect(originalError);
|
||||
|
||||
logger.error("");
|
||||
logger.error(err.stack);
|
||||
logger.error(originalErrorString);
|
||||
logger.error("");
|
||||
|
||||
const migrationName = (err.migration || undefined)?.name;
|
||||
if (typeof migrationName === "string") {
|
||||
prismaMigrations.setFailed(migrationName, err.stack);
|
||||
prismaMigrations.setFailed(migrationName, originalErrorString);
|
||||
}
|
||||
|
||||
process.exitCode = 1;
|
||||
|
||||
@@ -23,46 +23,49 @@ export default () => {
|
||||
// Uncomment to see the queries in console as the migration runs
|
||||
// log: ["query", "info", "warn", "error"],
|
||||
});
|
||||
return client.$transaction(async (prisma) => {
|
||||
const trees = await prisma.tree.findMany();
|
||||
const projects = await prisma.project.findMany();
|
||||
return client.$transaction(
|
||||
async (prisma) => {
|
||||
const trees = await prisma.tree.findMany();
|
||||
const projects = await prisma.project.findMany();
|
||||
|
||||
const builds: Prisma.BuildCreateManyInput[] = [];
|
||||
const builds: Prisma.BuildCreateManyInput[] = [];
|
||||
|
||||
for (const tree of trees) {
|
||||
const project = projects.find(
|
||||
(project) =>
|
||||
project.devTreeId === tree.id ||
|
||||
project.prodTreeId === tree.id ||
|
||||
TreeHistorySchema.parse(
|
||||
JSON.parse(project.prodTreeIdHistory)
|
||||
).includes(tree.id)
|
||||
);
|
||||
for (const tree of trees) {
|
||||
const project = projects.find(
|
||||
(project) =>
|
||||
project.devTreeId === tree.id ||
|
||||
project.prodTreeId === tree.id ||
|
||||
TreeHistorySchema.parse(
|
||||
JSON.parse(project.prodTreeIdHistory)
|
||||
).includes(tree.id)
|
||||
);
|
||||
|
||||
if (project === undefined) {
|
||||
continue;
|
||||
if (project === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const pages = PagesSchema.parse({
|
||||
homePage: {
|
||||
id: uuid(),
|
||||
name: "Home",
|
||||
path: "",
|
||||
title: "Home",
|
||||
meta: {},
|
||||
treeId: tree.id,
|
||||
},
|
||||
pages: [],
|
||||
});
|
||||
|
||||
builds.push({
|
||||
pages: JSON.stringify(pages),
|
||||
isDev: project.devTreeId === tree.id,
|
||||
isProd: project.prodTreeId === tree.id,
|
||||
projectId: project.id,
|
||||
});
|
||||
}
|
||||
|
||||
const pages = PagesSchema.parse({
|
||||
homePage: {
|
||||
id: uuid(),
|
||||
name: "Home",
|
||||
path: "",
|
||||
title: "Home",
|
||||
meta: {},
|
||||
treeId: tree.id,
|
||||
},
|
||||
pages: [],
|
||||
});
|
||||
|
||||
builds.push({
|
||||
pages: JSON.stringify(pages),
|
||||
isDev: project.devTreeId === tree.id,
|
||||
isProd: project.prodTreeId === tree.id,
|
||||
projectId: project.id,
|
||||
});
|
||||
}
|
||||
|
||||
await prisma.build.createMany({ data: builds });
|
||||
});
|
||||
await prisma.build.createMany({ data: builds });
|
||||
},
|
||||
{ timeout: 1000 * 60 }
|
||||
);
|
||||
};
|
||||
+22
-19
@@ -1,4 +1,3 @@
|
||||
import { assert } from "console";
|
||||
import { PrismaClient } from "./client";
|
||||
|
||||
// NOTE ON IMPORTS:
|
||||
@@ -12,22 +11,26 @@ import { PrismaClient } from "./client";
|
||||
|
||||
export default () => {
|
||||
const client = new PrismaClient();
|
||||
return client.$transaction(async (prisma) => {
|
||||
const previousAssets = await prisma.asset.findMany();
|
||||
const update = previousAssets.map((asset) => {
|
||||
return {
|
||||
id: asset.id,
|
||||
description: asset.alt,
|
||||
meta: JSON.stringify({
|
||||
width: Number(asset.width),
|
||||
height: Number(asset.height),
|
||||
}),
|
||||
};
|
||||
});
|
||||
await Promise.all(
|
||||
update.map(({ id, ...data }) =>
|
||||
prisma.asset.update({ where: { id }, data })
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
return client.$transaction(
|
||||
async (prisma) => {
|
||||
const previousAssets = await prisma.asset.findMany();
|
||||
const update = previousAssets.map((asset) => {
|
||||
return {
|
||||
id: asset.id,
|
||||
description: asset.alt,
|
||||
meta: JSON.stringify({
|
||||
width: Number(asset.width),
|
||||
height: Number(asset.height),
|
||||
}),
|
||||
};
|
||||
});
|
||||
await Promise.all(
|
||||
update.map(({ id, ...data }) =>
|
||||
prisma.asset.update({ where: { id }, data })
|
||||
)
|
||||
);
|
||||
},
|
||||
{ timeout: 1000 * 60 }
|
||||
);
|
||||
};
|
||||
+29
-26
@@ -20,34 +20,37 @@ export default () => {
|
||||
// Uncomment to see the queries in console as the migration runs
|
||||
// log: ["query", "info", "warn", "error"],
|
||||
});
|
||||
return client.$transaction(async (prisma) => {
|
||||
const builds = await prisma.build.findMany();
|
||||
const breakpoints = await prisma.breakpoints.findMany();
|
||||
return client.$transaction(
|
||||
async (prisma) => {
|
||||
const builds = await prisma.build.findMany();
|
||||
const breakpoints = await prisma.breakpoints.findMany();
|
||||
|
||||
const buildsParsed = builds.map((build) => ({
|
||||
id: build.id,
|
||||
pages: PagesSchema.parse(JSON.parse(build.pages)),
|
||||
}));
|
||||
const buildsParsed = builds.map((build) => ({
|
||||
id: build.id,
|
||||
pages: PagesSchema.parse(JSON.parse(build.pages)),
|
||||
}));
|
||||
|
||||
await Promise.all(
|
||||
breakpoints.map((breakpoint) => {
|
||||
const build = buildsParsed.find(
|
||||
(build) => build.pages.homePage.treeId === breakpoint.treeId
|
||||
);
|
||||
|
||||
if (build === undefined) {
|
||||
throw new Error(
|
||||
`Build not found for breakpoint ${breakpoint.treeId}`
|
||||
await Promise.all(
|
||||
breakpoints.map((breakpoint) => {
|
||||
const build = buildsParsed.find(
|
||||
(build) => build.pages.homePage.treeId === breakpoint.treeId
|
||||
);
|
||||
}
|
||||
|
||||
return prisma.breakpoints.update({
|
||||
where: { treeId: breakpoint.treeId },
|
||||
data: {
|
||||
buildId: build.id,
|
||||
},
|
||||
});
|
||||
})
|
||||
);
|
||||
});
|
||||
if (build === undefined) {
|
||||
throw new Error(
|
||||
`Build not found for breakpoint ${breakpoint.treeId}`
|
||||
);
|
||||
}
|
||||
|
||||
return prisma.breakpoints.update({
|
||||
where: { treeId: breakpoint.treeId },
|
||||
data: {
|
||||
buildId: build.id,
|
||||
},
|
||||
});
|
||||
})
|
||||
);
|
||||
},
|
||||
{ timeout: 1000 * 60 }
|
||||
);
|
||||
};
|
||||
@@ -33,5 +33,5 @@ export default () => {
|
||||
// NOTE:
|
||||
// Don't do any schema modifications here like adding a column to a table!
|
||||
// If you need to change schema, edit schema.prisma and create a schema migration.
|
||||
});
|
||||
}, { timeout: 1000 * 60 });
|
||||
};
|
||||
Reference in new issue
Block a user