diff --git a/src/controllers/organization.controller.js b/src/controllers/organization.controller.js index 1b4ac928..96a99ca6 100644 --- a/src/controllers/organization.controller.js +++ b/src/controllers/organization.controller.js @@ -208,7 +208,7 @@ export const subscribeToOrganization = async (req, res) => { }; export const deleteOrganization = async (req, res) => { - const { orgUid } = req.body; + const { orgUid } = req.params; try { const organization = await Organization.findOne({ @@ -233,20 +233,18 @@ export const deleteOrganization = async (req, res) => { } try { - // need to call this here because the task that normally does it cannot if there's no record of the organization + // need to call this here because the task that normally unsubscribes cannot if there's no record of the organization await Organization.unsubscribeFromOrganizationStores(organization); } catch (error) { return res.status(400).json({ - message: - 'Removed all organization records from cadt, but an error prevented unsubscribing from the organization on datalayer', + message: `Removed all organization records for organization ${orgUid} from cadt, but an error prevented unsubscribing from the organization on datalayer`, error: error.message, success: false, }); } return res.json({ - message: - 'Removed all organization records and unsubscribed from organization datalayer stores. cadt will not sync the organizations data from datalayer', + message: `Removed all organization records for organization ${orgUid} and unsubscribed from organization datalayer stores. cadt will not sync the organizations data from datalayer`, success: true, }); } catch (error) { @@ -296,7 +294,7 @@ export const unsubscribeFromOrganization = async (req, res) => { } const { storeIds: subscriptions, success: successGettingSubscriptions } = - getSubscriptions(); + await getSubscriptions(); if (!successGettingSubscriptions) { throw new Error('failed to get subscribed stores from datalayer'); } diff --git a/src/datalayer/syncService.js b/src/datalayer/syncService.js index 1f614bfb..99c697b3 100644 --- a/src/datalayer/syncService.js +++ b/src/datalayer/syncService.js @@ -52,15 +52,29 @@ const subscribeToStoreOnDataLayer = async (storeId) => { /** * gets and decodes data from a subscribed store. * will subscribe to any store id for which there is no subscription. - * @param storeId to retrieve data from + * + * providing a subscription list will prevent calling the datalayer `/subscriptions` RPC. + * good idea if calling in a loop + * + * @param storeId {string} to retrieve data from + * @param providedSubscriptions {[string] | undefined} optional list of subscriptions. providing prevents RPC call * @returns {Promise} */ -const getSubscribedStoreData = async (storeId) => { - const { storeIds: subscriptions, success } = - await dataLayer.getSubscriptions(); - if (!success) { - throw new Error('failed to retrieve subscriptions from datalayer'); +const getSubscribedStoreData = async ( + storeId, + providedSubscriptions = undefined, +) => { + let subscriptions = providedSubscriptions; + if (!subscriptions) { + const { storeIds: rpcSubscriptions, success } = + await dataLayer.getSubscriptions(); + if (!success) { + throw new Error('failed to retrieve subscriptions from datalayer'); + } + + subscriptions = rpcSubscriptions; } + const alreadySubscribed = subscriptions.includes(storeId); if (!alreadySubscribed) { diff --git a/src/models/organizations/organizations.model.js b/src/models/organizations/organizations.model.js index cf8a90cb..ca5dc450 100644 --- a/src/models/organizations/organizations.model.js +++ b/src/models/organizations/organizations.model.js @@ -21,7 +21,10 @@ import { getSubscriptions, getSyncStatus, } from '../../datalayer/persistance.js'; -import { addOrDeleteOrganizationRecordMutex } from '../../utils/model-utils.js'; +import { + addOrDeleteOrganizationRecordMutex, + processingSyncRegistriesTransactionMutex, +} from '../../utils/model-utils.js'; class Organization extends Model { static async getHomeOrg(includeAddress = true) { @@ -620,7 +623,7 @@ class Organization extends Model { onTimeout(error); } logger.debug(`${error.message}. RETRYING`); - await new Promise((resolve) => setTimeout(resolve, 3000)); + await new Promise((resolve) => setTimeout(resolve, 10000)); } } @@ -669,7 +672,7 @@ class Organization extends Model { * @returns {Promise} */ static async unsubscribeFromOrganizationStores(organizationStores) { - const { storeIds: subscriptionIds, success } = getSubscriptions(); + const { storeIds: subscriptionIds, success } = await getSubscriptions(); if (!success) { throw new Error('failed to get subscriptions from datalayer'); } @@ -729,17 +732,25 @@ class Organization extends Model { * @param orgUid */ static async deleteAllOrganizationData(orgUid) { - logger.verbose('acquiring mutex to import organization'); - const releaseMutex = await addOrDeleteOrganizationRecordMutex.acquire(); + logger.verbose('acquiring add/delete org mutex to delete organization'); + const releaseAddDeleteMutex = + await addOrDeleteOrganizationRecordMutex.acquire(); + + logger.verbose( + 'acquiring processingSyncRegistriesTransaction mutex to delete organization', + ); + const releaseAuditTransactionMutex = + await processingSyncRegistriesTransactionMutex.acquire(); const transaction = await sequelize.transaction(); try { - for (const model of ModelKeys) { - await model.destroy({ where: { orgUid }, transaction }); + await Organization.destroy({ where: { orgUid }, transaction }); + + for (const modelKey of Object.keys(ModelKeys)) { + await ModelKeys[modelKey].destroy({ where: { orgUid }, transaction }); } - await Staging.truncate(); - await Organization.destroy({ where: { orgUid }, transaction }); + await Staging.truncate({ transaction }); await FileStore.destroy({ where: { orgUid }, transaction }); await Audit.destroy({ where: { orgUid }, transaction }); @@ -755,7 +766,8 @@ class Organization extends Model { `an error occurred while deleting records corresponding to organization ${orgUid}. no changes have been made`, ); } finally { - releaseMutex(); + releaseAddDeleteMutex(); + releaseAuditTransactionMutex(); } } diff --git a/src/routes/v1/resources/organization.js b/src/routes/v1/resources/organization.js index e32696db..30bffe8a 100644 --- a/src/routes/v1/resources/organization.js +++ b/src/routes/v1/resources/organization.js @@ -14,7 +14,6 @@ import { removeMirrorSchema, addMirrorSchema, getMetaDataSchema, - deleteOrganizationSchema, } from '../../../validations'; const validator = joiExpress.createValidator({ passError: true }); @@ -37,13 +36,9 @@ OrganizationRouter.post('/sync', (req, res) => { return OrganizationController.sync(req, res); }); -OrganizationRouter.delete( - '/', - validator.query(deleteOrganizationSchema), - (req, res) => { - return OrganizationController.deleteOrganization(req, res); - }, -); +OrganizationRouter.delete('/:orgUid', (req, res) => { + return OrganizationController.deleteOrganization(req, res); +}); OrganizationRouter.post( '/', diff --git a/src/tasks/mirror-check.js b/src/tasks/mirror-check.js index 04c4348c..ff0004b6 100644 --- a/src/tasks/mirror-check.js +++ b/src/tasks/mirror-check.js @@ -85,10 +85,12 @@ const runMirrorCheck = async () => { const organizations = await Organization.getOrgsMap(); const orgs = Object.keys(organizations); for (const org of orgs) { - const orgData = organizations[org]; - await Organization.addMirror(orgData.orgUid, mirrorUrl, true); - await Organization.addMirror(orgData.dataModelVersionStoreId, true); - await Organization.addMirror(orgData.registryId, mirrorUrl, true); + if (org?.subscribed) { + const orgData = organizations[org]; + await Organization.addMirror(orgData.orgUid, mirrorUrl, true); + await Organization.addMirror(orgData.dataModelVersionStoreId, true); + await Organization.addMirror(orgData.registryId, mirrorUrl, true); + } } }; diff --git a/src/tasks/sync-registries.js b/src/tasks/sync-registries.js index 732ff985..99c263d8 100644 --- a/src/tasks/sync-registries.js +++ b/src/tasks/sync-registries.js @@ -65,6 +65,10 @@ const task = new Task('sync-registries', async () => { } finally { releaseSyncTaskMutex(); } + } else { + logger.debug( + 'could not acquire sync registries mutex. trying again shortly', + ); } }); diff --git a/src/validations/organizations.validations.js b/src/validations/organizations.validations.js index eaad09e0..8ce93191 100644 --- a/src/validations/organizations.validations.js +++ b/src/validations/organizations.validations.js @@ -10,10 +10,6 @@ export const importOrganizationSchema = Joi.object({ isHome: Joi.bool().optional(), }); -export const deleteOrganizationSchema = Joi.object({ - orgUid: Joi.string().required(), -}); - export const unsubscribeOrganizationSchema = Joi.object({ orgUid: Joi.string().required(), });