diff --git a/app/sync/__tests__/sync.test.js b/app/sync/__tests__/sync.test.js index 342a2264c..83dfaa3d5 100644 --- a/app/sync/__tests__/sync.test.js +++ b/app/sync/__tests__/sync.test.js @@ -250,6 +250,7 @@ describe('Integration tests for creating Resources and pushing', () => { // Flush changes just to be sure they won't affect our tests await db.flushChanges(); + await sync.writePendingChanges(); // Assert that all our new models were created expect((await models.workspace.all()).length).toBe(2); @@ -280,6 +281,7 @@ describe('Integration tests for creating Resources and pushing', () => { }); await db.flushChanges(); + await sync.writePendingChanges(); await sync.push(); // Push changes and get resource @@ -311,6 +313,7 @@ describe('Integration tests for creating Resources and pushing', () => { parentId: 'wrk_1' }); await db.flushChanges(); + await sync.writePendingChanges(); await sync.push(); // Mark resource as removed @@ -324,6 +327,7 @@ describe('Integration tests for creating Resources and pushing', () => { db.bufferChanges(); await models.request.update(request, {name: 'New Name'}); await db.flushChanges(); + await sync.writePendingChanges(); await sync.push(); const finalResource = await syncStorage.getResourceByDocId('req_t'); @@ -342,6 +346,7 @@ describe('Integration tests for creating Resources and pushing', () => { // Drain and fetch new resource await db.flushChanges(); + await sync.writePendingChanges(); await sync.push(); const updatedResource = await syncStorage.getResourceByDocId(request._id); @@ -370,6 +375,7 @@ describe('Integration tests for creating Resources and pushing', () => { // Drain and fetch new resource await db.flushChanges(); + await sync.writePendingChanges(); await sync.push(); const updatedResource = await syncStorage.getResourceByDocId(request._id); diff --git a/app/sync/index.js b/app/sync/index.js index 5f6f93dd4..d39efa3d8 100644 --- a/app/sync/index.js +++ b/app/sync/index.js @@ -10,6 +10,7 @@ import {trackEvent} from '../analytics/index'; export const START_DELAY = 1E3; export const PULL_PERIOD = 15E3; export const PUSH_PERIOD = 10E3; +export const WRITE_PERIOD = 1E3; const WHITE_LIST = { [models.workspace.type]: true, @@ -26,6 +27,8 @@ const NO_VERSION = '__NO_VERSION__'; const resourceGroupSymmetricKeysCache = {}; let _pullChangesInterval = null; let _pushChangesInterval = null; +let _writeChangesInterval = null; +let _pendingDBChanges = {}; let _isInitialized = false; export async function init () { @@ -36,7 +39,6 @@ export async function init () { // NOTE: This is at the top to prevent race conditions _isInitialized = true; - db.onChange(async changes => { // To help prevent bugs, put Workspaces first const sortedChanges = changes.sort( @@ -44,7 +46,6 @@ export async function init () { ); for (const [event, doc, fromSync] of sortedChanges) { - const notOnWhitelist = !WHITE_LIST[doc.type]; const notLoggedIn = !session.isLoggedIn(); @@ -52,7 +53,8 @@ export async function init () { continue; } - await _handleChangeAndPush(event, doc, Date.now()); + const key = `${event}:${doc._id}`; + _pendingDBChanges[key] = [event, doc, Date.now()]; } }); @@ -62,6 +64,7 @@ export async function init () { _pullChangesInterval = setInterval(pull, PULL_PERIOD); _pushChangesInterval = setInterval(push, PUSH_PERIOD); + _writeChangesInterval = setInterval(writePendingChanges, WRITE_PERIOD); logger.debug('Initialized'); } @@ -71,6 +74,7 @@ export function _testReset () { _isInitialized = false; clearInterval(_pullChangesInterval); clearInterval(_pushChangesInterval); + clearInterval(_writeChangesInterval); } /** @@ -128,6 +132,24 @@ export async function fixDuplicateResourceGroups () { } } +export async function writePendingChanges () { + // First make a copy and clear pending changes + const changes = Object.assign({}, _pendingDBChanges); + _pendingDBChanges = {}; + + const keys = Object.keys(changes); + + if (keys.length === 0) { + // No changes, just return + return; + } + + for (const key of Object.keys(changes)) { + const [event, doc, timestamp] = changes[key]; + await _handleChangeAndPush(event, doc, timestamp); + } +} + export async function push (resourceGroupId = null) { if (!session.isLoggedIn()) { return; diff --git a/app/ui/containers/App.js b/app/ui/containers/App.js index fcd5d546f..328abfce7 100644 --- a/app/ui/containers/App.js +++ b/app/ui/containers/App.js @@ -356,13 +356,14 @@ class App extends Component { // Force refresh if environment changes if (doc.type === models.environment.type) { + console.log('[App] Forcing update from environment change', change); this._wrapper.forceRequestPaneRefresh(); } // Force refresh if sync changes the active request if (fromSync && doc._id === activeRequest._id) { this._wrapper.forceRequestPaneRefresh(); - console.log('[App] Forcing update'); + console.log('[App] Forcing update from request change', change); } } });