Merge branch 'main' into 252-fonts-manager-and-fonts-selector-font-upload

This commit is contained in:
Oleg Isonen authored and GitHub committed 2022-09-16 09:56:05 +02:00
commit 6926fd30fd
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 }
);
};
@@ -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 }
);
};
@@ -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 });
};