remove mapAsyncDialects

This commit is contained in:
Marc-Roig 2023-02-06 15:39:47 +01:00
parent 4f4b424197
commit 02d467f933
5 changed files with 64 additions and 66 deletions

View File

@ -3,10 +3,12 @@
const _ = require('lodash');
const { has, prop, omit, toString, pipe, assign } = require('lodash/fp');
const { contentTypes: contentTypesUtils, mapAsyncDialects } = require('@strapi/utils');
const { contentTypes: contentTypesUtils, mapAsync } = require('@strapi/utils');
const { ApplicationError } = require('@strapi/utils').errors;
const { getComponentAttributes } = require('@strapi/utils').contentTypes;
const isDialectMySQL = () => strapi.db.dialect.client === 'mysql';
const omitComponentData = (contentType, data) => {
const { attributes } = contentType;
const componentAttributes = Object.keys(attributes).filter((attributeName) =>
@ -43,8 +45,11 @@ const createComponents = async (uid, data) => {
throw new Error('Expected an array to create repeatable component');
}
const components = await mapAsyncDialects(componentValue, (value) =>
createComponent(componentUID, value)
// MySQL/MariaDB can cause deadlocks here if concurrency higher than 1
const components = await mapAsync(
componentValue,
(value) => createComponent(componentUID, value),
{ concurrency: isDialectMySQL() ? 1 : Infinity }
);
componentBody[attributeName] = components.map(({ id }) => {
@ -77,16 +82,21 @@ const createComponents = async (uid, data) => {
throw new Error('Expected an array to create repeatable component');
}
componentBody[attributeName] = await mapAsyncDialects(dynamiczoneValues, async (value) => {
const { id } = await createComponent(value.__component, value);
return {
id,
__component: value.__component,
__pivot: {
field: attributeName,
},
};
});
// MySQL/MariaDB can cause deadlocks here if concurrency higher than 1
componentBody[attributeName] = await mapAsync(
dynamiczoneValues,
async (value) => {
const { id } = await createComponent(value.__component, value);
return {
id,
__component: value.__component,
__pivot: {
field: attributeName,
},
};
},
{ concurrency: isDialectMySQL() ? 1 : Infinity }
);
continue;
}
@ -135,8 +145,11 @@ const updateComponents = async (uid, entityToUpdate, data) => {
throw new Error('Expected an array to create repeatable component');
}
const components = await mapAsyncDialects(componentValue, (value) =>
updateOrCreateComponent(componentUID, value)
// MySQL/MariaDB can cause deadlocks here if concurrency higher than 1
const components = await mapAsync(
componentValue,
(value) => updateOrCreateComponent(componentUID, value),
{ concurrency: isDialectMySQL() ? 1 : Infinity }
);
componentBody[attributeName] = components.filter(_.negate(_.isNil)).map(({ id }) => {
@ -171,17 +184,22 @@ const updateComponents = async (uid, entityToUpdate, data) => {
throw new Error('Expected an array to create repeatable component');
}
componentBody[attributeName] = await mapAsyncDialects(dynamiczoneValues, async (value) => {
const { id } = await updateOrCreateComponent(value.__component, value);
// MySQL/MariaDB can cause deadlocks here if concurrency higher than 1
componentBody[attributeName] = await mapAsync(
dynamiczoneValues,
async (value) => {
const { id } = await updateOrCreateComponent(value.__component, value);
return {
id,
__component: value.__component,
__pivot: {
field: attributeName,
},
};
});
return {
id,
__component: value.__component,
__pivot: {
field: attributeName,
},
};
},
{ concurrency: isDialectMySQL() ? 1 : Infinity }
);
continue;
}
@ -283,17 +301,17 @@ const deleteComponents = async (uid, entityToDelete, { loadComponents = true } =
if (attribute.type === 'component') {
const { component: componentUID } = attribute;
await mapAsyncDialects(_.castArray(value), (subValue) =>
deleteComponent(componentUID, subValue)
);
for (const subValue of _.castArray(value)) {
await deleteComponent(componentUID, subValue);
}
// MySQL/MariaDB can cause deadlocks here if concurrency higher than 1
await mapAsync(_.castArray(value), (subValue) => deleteComponent(componentUID, subValue), {
concurrency: isDialectMySQL() ? 1 : Infinity,
});
} else {
// delete dynamic zone components
await mapAsyncDialects(_.castArray(value), (subValue) =>
deleteComponent(subValue.__component, subValue)
// MySQL/MariaDB can cause deadlocks here if concurrency higher than 1
await mapAsync(
_.castArray(value),
(subValue) => deleteComponent(subValue.__component, subValue),
{ concurrency: isDialectMySQL() ? 1 : Infinity }
);
}

View File

@ -4,9 +4,3 @@ export type MapAsync<T = any, R = any> = lodash.CurriedFunction3<
{ concurrency?: number },
Promise<R[]>
>;
export type MapAsyncDialects<T = any, R = any> = (
array: T[],
func: (element: T, index: number) => R | Promise<R>,
options?: { concurrency?: number }
) => Promise<R[]>;

View File

@ -20,24 +20,7 @@ function pipeAsync(...methods) {
*/
const mapAsync = curry(pMap);
/**
* Because of how mysql works, making parallel requests can cause deadlocks.
* This function will run the requests sequentially if mysql is used. Else,
* it will encapsulate them in a Promise.all.
*
* @type { import('./async').MapAsyncDialects }
*/
const mapAsyncDialects = async (array, func, options = {}) => {
switch (strapi.db.dialect.client) {
case 'mysql':
return mapAsync(array, func, { concurrency: 1 });
default:
return mapAsync(array, func, options);
}
};
module.exports = {
mapAsync,
mapAsyncDialects,
pipeAsync,
};

View File

@ -37,7 +37,7 @@ const providerFactory = require('./provider-factory');
const pagination = require('./pagination');
const sanitize = require('./sanitize');
const traverseEntity = require('./traverse-entity');
const { pipeAsync, mapAsync, mapAsyncDialects } = require('./async');
const { pipeAsync, mapAsync } = require('./async');
const convertQueryParams = require('./convert-query-params');
const importDefault = require('./import-default');
const template = require('./template');
@ -82,7 +82,6 @@ module.exports = {
pagination,
pipeAsync,
mapAsync,
mapAsyncDialects,
errors,
validateYupSchema,
validateYupSchemaSync,

View File

@ -2,9 +2,11 @@
const { prop, isNil, isEmpty } = require('lodash/fp');
const { mapAsyncDialects } = require('@strapi/utils');
const { mapAsync } = require('@strapi/utils');
const { getService } = require('../utils');
const isDialectMySQL = () => strapi.db.dialect.client === 'mysql';
/**
* Adds the default locale to an object if it isn't defined yet
* @param {Object} data a data object before being persisted into db
@ -33,9 +35,10 @@ const syncLocalizations = async (entry, { model }) => {
return strapi.query(model.uid).update({ where: { id }, data: { localizations } });
};
await mapAsyncDialects(entry.localizations, (localization) =>
updateLocalization(localization.id)
);
// MySQL/MariaDB can cause deadlocks here if concurrency higher than 1
await mapAsync(entry.localizations, (localization) => updateLocalization(localization.id), {
concurrency: isDialectMySQL() ? 1 : undefined,
});
}
};
@ -59,9 +62,10 @@ const syncNonLocalizedAttributes = async (entry, { model }) => {
return strapi.entityService.update(model.uid, id, { data: nonLocalizedAttributes });
};
await mapAsyncDialects(entry.localizations, (localization) =>
updateLocalization(localization.id)
);
// MySQL/MariaDB can cause deadlocks here if concurrency higher than 1
await mapAsync(entry.localizations, (localization) => updateLocalization(localization.id), {
concurrency: isDialectMySQL() ? 1 : undefined,
});
}
};