fix: Reduce size of teamPermanentDeleter transactions for reliability

This commit is contained in:
Tom Moor
2024-04-18 09:32:13 -04:00
parent 18129a4bbb
commit 6b6156b032

View File

@@ -1,4 +1,3 @@
import { Transaction } from "sequelize";
import Logger from "@server/logging/Logger"; import Logger from "@server/logging/Logger";
import { traceFunction } from "@server/logging/tracing"; import { traceFunction } from "@server/logging/tracing";
import { import {
@@ -20,6 +19,13 @@ import {
} from "@server/models"; } from "@server/models";
import { sequelize } from "@server/storage/database"; import { sequelize } from "@server/storage/database";
/**
* Permanently deletes a team and all related data from the database. Note that this does not happen
* in a single transaction due to the potential size of such a transaction, so it is possible for
* the operation to be interrupted and leave partial data. In which case it can be safely re-run.
*
* @param team - The team to delete.
*/
async function teamPermanentDeleter(team: Team) { async function teamPermanentDeleter(team: Team) {
if (!team.deletedAt) { if (!team.deletedAt) {
throw new Error( throw new Error(
@@ -32,19 +38,17 @@ async function teamPermanentDeleter(team: Team) {
`Permanently destroying team ${team.name} (${team.id})` `Permanently destroying team ${team.name} (${team.id})`
); );
const teamId = team.id; const teamId = team.id;
let transaction!: Transaction;
try { await Attachment.findAllInBatches<Attachment>(
transaction = await sequelize.transaction(); {
await Attachment.findAllInBatches<Attachment>( where: {
{ teamId,
where: {
teamId,
},
limit: 100,
offset: 0,
}, },
async (attachments, options) => { limit: 100,
offset: 0,
},
async (attachments, options) => {
await sequelize.transaction(async (transaction) => {
Logger.info( Logger.info(
"commands", "commands",
`Deleting attachments ${options.offset} ${ `Deleting attachments ${options.offset} ${
@@ -58,19 +62,22 @@ async function teamPermanentDeleter(team: Team) {
}) })
) )
); );
} });
); }
// Destroy user-relation models );
await User.findAllInBatches<User>(
{ // Destroy user-relation models
attributes: ["id"], await User.findAllInBatches<User>(
where: { {
teamId, attributes: ["id"],
}, where: {
limit: 100, teamId,
offset: 0,
}, },
async (users) => { limit: 100,
offset: 0,
},
async (users) => {
await sequelize.transaction(async (transaction) => {
const userIds = users.map((user) => user.id); const userIds = users.map((user) => user.id);
await UserAuthentication.destroy({ await UserAuthentication.destroy({
where: { where: {
@@ -79,6 +86,13 @@ async function teamPermanentDeleter(team: Team) {
force: true, force: true,
transaction, transaction,
}); });
await Attachment.destroy({
where: {
userId: userIds,
},
force: true,
transaction,
});
await ApiKey.destroy({ await ApiKey.destroy({
where: { where: {
userId: userIds, userId: userIds,
@@ -93,9 +107,12 @@ async function teamPermanentDeleter(team: Team) {
force: true, force: true,
transaction, transaction,
}); });
} });
); }
// Destory team-relation models );
// Destory team-relation models
await sequelize.transaction(async (transaction) => {
await AuthenticationProvider.destroy({ await AuthenticationProvider.destroy({
where: { where: {
teamId, teamId,
@@ -180,14 +197,7 @@ async function teamPermanentDeleter(team: Team) {
transaction, transaction,
} }
); );
await transaction.commit(); });
} catch (err) {
if (transaction) {
await transaction.rollback();
}
throw err;
}
} }
export default traceFunction({ export default traceFunction({