From c5e2bb24321b3304ea54cf163856a0160fbfa7c8 Mon Sep 17 00:00:00 2001 From: Jori Lallo Date: Sat, 9 Dec 2017 15:04:55 -0800 Subject: [PATCH] Lock collection navigation tree changes --- server/models/Collection.js | 18 ++++++++++++++++++ server/redis.js | 5 ++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/server/models/Collection.js b/server/models/Collection.js index 8cfd45ee..73069c9a 100644 --- a/server/models/Collection.js +++ b/server/models/Collection.js @@ -2,6 +2,7 @@ import slug from 'slug'; import randomstring from 'randomstring'; import { DataTypes, sequelize } from '../sequelize'; +import { asyncLock } from '../redis'; import Document from './Document'; import Event from './Event'; import _ from 'lodash'; @@ -111,6 +112,9 @@ Collection.prototype.addDocumentToStructure = async function( index, }; + // documentStructure can only be updated by one request at the time + const unlock = await asyncLock(`collection-${this.id}`); + // If moving existing document with children, use existing structure to // keep everything in shape and not loose documents const documentJson = { @@ -158,6 +162,8 @@ Collection.prototype.addDocumentToStructure = async function( teamId: this.teamId, }); + unlock(); + return this; }; @@ -166,6 +172,10 @@ Collection.prototype.addDocumentToStructure = async function( */ Collection.prototype.updateDocument = async function(updatedDocument) { if (!this.documentStructure) return; + + // documentStructure can only be updated by one request at the time + const unlock = await asyncLock(`collection-${this.id}`); + const { id } = updatedDocument; const updateChildren = documents => { @@ -184,6 +194,7 @@ Collection.prototype.updateDocument = async function(updatedDocument) { this.documentStructure = updateChildren(this.documentStructure); await this.save(); + unlock(); return this; }; @@ -216,7 +227,12 @@ Collection.prototype.removeDocument = async function( options: DeleteDocumentOptions = { deleteDocument: true } ) { if (!this.documentStructure) return; + let returnValue; + + // documentStructure can only be updated by one request at the time + const unlock = await asyncLock('testLock'); + const existingData = { old: this.documentStructure, documentId: document, @@ -280,6 +296,8 @@ Collection.prototype.removeDocument = async function( teamId: this.teamId, }); + await unlock(); + return returnValue; }; diff --git a/server/redis.js b/server/redis.js index 11309366..182dedbf 100644 --- a/server/redis.js +++ b/server/redis.js @@ -5,4 +5,7 @@ import redisLock from 'redis-lock'; const client = redis.createClient(process.env.REDIS_URL); const lock = redisLock(client); -export { client, lock }; +const asyncLock = (lockName: string) => + new Promise(resolve => lock(lockName, unlock => resolve(unlock))); + +export { client, asyncLock };