From 3f6ecc00212a652465867cfb795d1e21dea8e91e Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Thu, 8 Feb 2018 02:07:44 -0500 Subject: [PATCH] Fix "Can't queue event outside of a transaction" If a transaction took over 30 seconds and another transaction timed out waiting for it, the second transaction would reset the notifier queue, but if the first transaction then tried to queue an event, it would fail with this error and roll back. (It would be nice to figure out why transactions are taking over 30 seconds, though.) --- chrome/content/zotero/xpcom/db.js | 10 ++++----- chrome/content/zotero/xpcom/notifier.js | 28 ++++++++++++++----------- chrome/content/zotero/xpcom/zotero.js | 6 +++--- test/tests/notifierTest.js | 21 +++++++++++++++++++ 4 files changed, 45 insertions(+), 20 deletions(-) diff --git a/chrome/content/zotero/xpcom/db.js b/chrome/content/zotero/xpcom/db.js index 305ac23dc..9450881d4 100644 --- a/chrome/content/zotero/xpcom/db.js +++ b/chrome/content/zotero/xpcom/db.js @@ -485,7 +485,7 @@ Zotero.DBConnection.prototype.executeTransaction = Zotero.Promise.coroutine(func // Run begin callbacks for (var i=0; i Zotero.Notifier.begin(id)); + Zotero.DB.addCallback('commit', id => Zotero.Notifier.commit(null, id)); + Zotero.DB.addCallback('rollback', id => Zotero.Notifier.reset(id)); try { // Require >=2.1b3 database to ensure proper locking diff --git a/test/tests/notifierTest.js b/test/tests/notifierTest.js index 1c49f1f4f..c803370ad 100644 --- a/test/tests/notifierTest.js +++ b/test/tests/notifierTest.js @@ -57,4 +57,25 @@ describe("Zotero.Notifier", function () { Zotero.Notifier.unregisterObserver(id); }); }); + + describe("#queue", function () { + it("should handle notification after DB timeout from another transaction", async function () { + var promise1 = Zotero.DB.executeTransaction(async function () { + var item = createUnsavedDataObject('item'); + await item.save(); + + await Zotero.Promise.delay(2000); + + Zotero.Notifier.queue('refresh', 'item', item.id); + }.bind(this)); + + var promise2 = Zotero.DB.executeTransaction(async function () { + var item = createUnsavedDataObject('item'); + await item.save(); + }.bind(this), { waitTimeout: 1000 }); + + await promise1; + assert.isTrue(promise2.isRejected()); + }); + }); });