From 4f975fc69603bc961e2db281929b4f0975047be1 Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Thu, 18 Jul 2024 13:04:29 -0400 Subject: [PATCH 1/9] fix subscription stopping too early --- packages/ddp-server/livedata_server.js | 59 +++++++++++++------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/packages/ddp-server/livedata_server.js b/packages/ddp-server/livedata_server.js index fce6e031a1..7010aedf44 100644 --- a/packages/ddp-server/livedata_server.js +++ b/packages/ddp-server/livedata_server.js @@ -396,13 +396,6 @@ var Session = function (server, version, socket, options) { }; Object.assign(Session.prototype, { - _checkPublishPromiseBeforeSend(f) { - if (!this._publishCursorPromise) { - f(); - return; - } - this._publishCursorPromise.finally(() => f()); - }, sendReady: function (subscriptionIds) { var self = this; if (self._isSending) { @@ -556,13 +549,11 @@ Object.assign(Session.prototype, { // It should be a JSON object (it will be stringified). send: function (msg) { const self = this; - this._checkPublishPromiseBeforeSend(() => { - if (self.socket) { - if (Meteor._printSentDDP) - Meteor._debug('Sent DDP', DDPCommon.stringifyDDP(msg)); - self.socket.send(DDPCommon.stringifyDDP(msg)); - } - }); + if (self.socket) { + if (Meteor._printSentDDP) + Meteor._debug("Sent DDP", DDPCommon.stringifyDDP(msg)); + self.socket.send(DDPCommon.stringifyDDP(msg)); + } }, // Send a connection error. @@ -627,6 +618,7 @@ Object.assign(Session.prototype, { var processNext = function () { var msg = self.inQueue && self.inQueue.shift(); + if (!msg) { self.workerRunning = false; return; @@ -653,6 +645,7 @@ Object.assign(Session.prototype, { msg, unblock ); + if (Meteor._isPromise(result)) { result.finally(() => unblock()); } else { @@ -1207,16 +1200,16 @@ Object.assign(Subscription.prototype, { resultOrThenable && typeof resultOrThenable.then === 'function'; if (isThenable) { try { - self._publishHandlerResult(await resultOrThenable); + await self._publishHandlerResult(await resultOrThenable); } catch(e) { self.error(e) } } else { - self._publishHandlerResult(resultOrThenable); + await self._publishHandlerResult(resultOrThenable); } }, - _publishHandlerResult: function (res) { + async _publishHandlerResult (res) { // SPECIAL CASE: Instead of writing their own callbacks that invoke // this.added/changed/ready/etc, the user can just return a collection // cursor or array of cursors from the publish function; we call their @@ -1239,11 +1232,15 @@ Object.assign(Subscription.prototype, { return c && c._publishCursor; }; if (isCursor(res)) { - this._publishCursorPromise = res._publishCursor(self).then(() => { - // _publishCursor only returns after the initial added callbacks have run. - // mark subscription as ready. - self.ready(); - }).catch((e) => self.error(e)); + try { + await res._publishCursor(self); + } catch (e) { + self.error(e); + return; + } + // _publishCursor only returns after the initial added callbacks have run. + // mark subscription as ready. + self.ready(); } else if (_.isArray(res)) { // Check all the elements are cursors if (! _.all(res, isCursor)) { @@ -1254,6 +1251,7 @@ Object.assign(Subscription.prototype, { // XXX we should support overlapping cursors, but that would require the // merge box to allow overlap within a subscription var collectionNames = {}; + for (var i = 0; i < res.length; ++i) { var collectionName = res[i]._getCollectionName(); if (_.has(collectionNames, collectionName)) { @@ -1265,13 +1263,15 @@ Object.assign(Subscription.prototype, { collectionNames[collectionName] = true; }; - this._publishCursorPromise = Promise.all( - res.map(c => c._publishCursor(self)) - ) - .then(() => { - self.ready(); - }) - .catch((e) => self.error(e)); + try { + for (const cur of res) { + await cur._publishCursor(self); + } + } catch (e) { + self.error(e); + return; + } + self.ready(); } else if (res) { // Truthy values other than cursors or arrays are probably a // user mistake (possible returning a Mongo document via, say, @@ -1409,7 +1409,6 @@ Object.assign(Subscription.prototype, { ids.add(id); } - this._session._publishCursorPromise = this._publishCursorPromise; this._session.added(this._subscriptionHandle, collectionName, id, fields); }, From 604e6b132e6d8cc553d6bc04bb46d7ddf6b1cc98 Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Fri, 19 Jul 2024 11:15:13 -0400 Subject: [PATCH 2/9] run operations in parallel --- packages/ddp-server/livedata_server.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/ddp-server/livedata_server.js b/packages/ddp-server/livedata_server.js index 7010aedf44..23d6336876 100644 --- a/packages/ddp-server/livedata_server.js +++ b/packages/ddp-server/livedata_server.js @@ -1261,12 +1261,10 @@ Object.assign(Subscription.prototype, { return; } collectionNames[collectionName] = true; - }; + } try { - for (const cur of res) { - await cur._publishCursor(self); - } + await Promise.all(res.map(cur => cur._publishCursor(self))); } catch (e) { self.error(e); return; From 4ca0a12b74f8c346159f29e9ef00c6746521049f Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Fri, 19 Jul 2024 12:27:13 -0400 Subject: [PATCH 3/9] add test --- packages/ddp-server/livedata_server_tests.js | 67 ++++++++++++++++++++ packages/ddp-server/package.js | 1 + 2 files changed, 68 insertions(+) diff --git a/packages/ddp-server/livedata_server_tests.js b/packages/ddp-server/livedata_server_tests.js index 445630b4c4..cbc4e33b1b 100644 --- a/packages/ddp-server/livedata_server_tests.js +++ b/packages/ddp-server/livedata_server_tests.js @@ -442,3 +442,70 @@ Tinytest.addAsync("livedata server - waiting for Promise", (test, onComplete) => .then(onComplete); }) ); + +Tinytest.addAsync('livedata server - publish cursor is properly awaited', async function (test) { + const messages = [] + + let sub = null; + + const { clientConn } = await getTestConnections(test) + + const send = clientConn._stream.send + + clientConn._stream.send = function (...args) { + send.apply(this, args) + messages.push(args[0]) + } + + clientConn._stream.on('message', message => messages.push(message)); + + const coll = new Mongo.Collection('items', { + defineMutationMethods: false, + }); + + for (let i = 0; i < 10; i++) { + await coll.removeAsync({ _id: `item_${i}` }) + await coll.insertAsync({ _id: `item_${i}`, title: `Item #${i}` }); + } + + delete Meteor.server.publish_handlers['asyncPublishCursor']; + + Meteor.publish('asyncPublishCursor', async function (count) { + return coll.find({}, { limit: count }); + }); + + const reactiveVar = new ReactiveVar(1); + + const computation = Tracker.autorun(() => { + sub = clientConn.subscribe('asyncPublishCursor', reactiveVar.get()); + }); + + await sleep(100) + + reactiveVar.set(2); + + await sleep(100) + + const expectedMessages = ['sub', 'added', 'ready', 'sub', 'unsub', 'added', 'ready', 'nosub'] + + /** + * There shouldn't ever be `removed` messages here, otherwise the UI will glitch + */ + const parsedMessages = messages.map(m => EJSON.parse(m).msg) + + test.equal(parsedMessages, expectedMessages) + + computation.stop(); +}); + +function getTestConnections(test) { + return new Promise((resolve, reject) => { + makeTestConnection(test, (clientConn, serverConn) => { + resolve({ clientConn, serverConn }); + }, reject); + }) +} + +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} \ No newline at end of file diff --git a/packages/ddp-server/package.js b/packages/ddp-server/package.js index 771ac4909a..2b04188333 100644 --- a/packages/ddp-server/package.js +++ b/packages/ddp-server/package.js @@ -49,6 +49,7 @@ Package.onUse(function (api) { Package.onTest(function (api) { api.use('ecmascript', ['client', 'server']); + api.use('ejson', ['client', 'server']); api.use('livedata', ['client', 'server']); api.use('mongo', ['client', 'server']); api.use('test-helpers', ['client', 'server']); From bc55ac272189da12055fc2c105bf6af321df577e Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Fri, 19 Jul 2024 12:33:20 -0400 Subject: [PATCH 4/9] shrinkwraps --- .../.npm/package/npm-shrinkwrap.json | 6 +- .../.npm/package/npm-shrinkwrap.json | 6 +- .../email/.npm/package/npm-shrinkwrap.json | 6 +- .../.npm/package/npm-shrinkwrap.json | 72 +++++++++---------- .../webapp/.npm/package/npm-shrinkwrap.json | 21 ++++-- 5 files changed, 59 insertions(+), 52 deletions(-) diff --git a/packages/accounts-2fa/.npm/package/npm-shrinkwrap.json b/packages/accounts-2fa/.npm/package/npm-shrinkwrap.json index 9f9042977e..09ae94aaeb 100644 --- a/packages/accounts-2fa/.npm/package/npm-shrinkwrap.json +++ b/packages/accounts-2fa/.npm/package/npm-shrinkwrap.json @@ -2,9 +2,9 @@ "lockfileVersion": 4, "dependencies": { "@types/node": { - "version": "20.14.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", - "integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==" + "version": "20.14.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.11.tgz", + "integrity": "sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==" }, "@types/notp": { "version": "2.0.5", diff --git a/packages/accounts-password/.npm/package/npm-shrinkwrap.json b/packages/accounts-password/.npm/package/npm-shrinkwrap.json index bea360b61d..62d088c856 100644 --- a/packages/accounts-password/.npm/package/npm-shrinkwrap.json +++ b/packages/accounts-password/.npm/package/npm-shrinkwrap.json @@ -233,9 +233,9 @@ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, "semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==" + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==" }, "set-blocking": { "version": "2.0.0", diff --git a/packages/email/.npm/package/npm-shrinkwrap.json b/packages/email/.npm/package/npm-shrinkwrap.json index c43eb6a9ea..17f1728a37 100644 --- a/packages/email/.npm/package/npm-shrinkwrap.json +++ b/packages/email/.npm/package/npm-shrinkwrap.json @@ -2,9 +2,9 @@ "lockfileVersion": 4, "dependencies": { "@types/node": { - "version": "20.14.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", - "integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==" + "version": "20.14.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.11.tgz", + "integrity": "sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==" }, "@types/nodemailer": { "version": "6.4.14", diff --git a/packages/npm-mongo/.npm/package/npm-shrinkwrap.json b/packages/npm-mongo/.npm/package/npm-shrinkwrap.json index 66bce6a75a..a318cf8cba 100644 --- a/packages/npm-mongo/.npm/package/npm-shrinkwrap.json +++ b/packages/npm-mongo/.npm/package/npm-shrinkwrap.json @@ -181,9 +181,9 @@ "integrity": "sha512-15ElZT88peoHnq5TEoEtZwoXTXRxNrk60TZNdpl/TUBJ5oNJ9Dqb5Z4ryb8ofN6nm9aFf59GVAerFDz8iUoHBA==" }, "@mongodb-js/saslprep": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.7.tgz", - "integrity": "sha512-dCHW/oEX0KJ4NjDULBo3JiOaK5+6axtpBbS+ao2ZInoAL9/YRQLhXzSNAFz7hP4nzLkIqsfYAK/PDE3+XHny0Q==" + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.8.tgz", + "integrity": "sha512-qKwC/M/nNNaKUBMQ0nuzm47b7ZYWQHN3pcXq4IIcoSBc2hOIrflAxJduIvvqmhoz3gR2TacTAs8vlsCVPkiEdQ==" }, "@smithy/abort-controller": { "version": "3.1.1", @@ -196,9 +196,9 @@ "integrity": "sha512-SkW5LxfkSI1bUC74OtfBbdz+grQXYiPYolyu8VfpLIjEoN/sHVBlLeGXMQ1vX4ejkgfv6sxVbQJ32yF2cl1veA==" }, "@smithy/core": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.2.6.tgz", - "integrity": "sha512-tBbVIv/ui7/lLTKayYJJvi8JLVL2SwOQTbNFEOrvzSE3ktByvsa1erwBOnAMo8N5Vu30g7lN4lLStrU75oDGuw==" + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.2.7.tgz", + "integrity": "sha512-Wwd9QWKaYdR+n/oIqJbuwSr9lHuv7sa1e3Zu4wIToZl0sS7xapTYYqQtXP1hKKtIWz0jl8AhvOfNwkfT5jjV0w==" }, "@smithy/credential-provider-imds": { "version": "3.1.4", @@ -206,9 +206,9 @@ "integrity": "sha512-NKyH01m97Xa5xf3pB2QOF3lnuE8RIK0hTVNU5zvZAwZU8uspYO4DHQVlK+Y5gwSrujTfHvbfd1D9UFJAc0iYKQ==" }, "@smithy/fetch-http-handler": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.1.tgz", - "integrity": "sha512-0w0bgUvZmfa0vHN8a+moByhCJT07WN6AHKEhFSOLsDpnszm+5dLVv5utGaqbhOrZ/aF5x3xuPMs/oMCd+4O5xg==" + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.2.tgz", + "integrity": "sha512-3LaWlBZObyGrOOd7e5MlacnAKEwFBmAeiW/TOj2eR9475Vnq30uS2510+tnKbxrGjROfNdOhQqGo5j3sqLT6bA==" }, "@smithy/hash-node": { "version": "3.0.3", @@ -226,9 +226,9 @@ "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==" }, "@smithy/middleware-content-length": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.3.tgz", - "integrity": "sha512-Dbz2bzexReYIQDWMr+gZhpwBetNXzbhnEMhYKA6urqmojO14CsXjnsoPYO8UL/xxcawn8ZsuVU61ElkLSltIUQ==" + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.4.tgz", + "integrity": "sha512-wySGje/KfhsnF8YSh9hP16pZcl3C+X6zRsvSfItQGvCyte92LliilU3SD0nR7kTlxnAJwxY8vE/k4Eoezj847Q==" }, "@smithy/middleware-endpoint": { "version": "3.0.5", @@ -236,9 +236,9 @@ "integrity": "sha512-V4acqqrh5tDxUEGVTOgf2lYMZqPQsoGntCrjrJZEeBzEzDry2d2vcI1QCXhGltXPPY+BMc6eksZMguA9fIY8vA==" }, "@smithy/middleware-retry": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.9.tgz", - "integrity": "sha512-Mrv9omExU1gA7Y0VEJG2LieGfPYtwwcEiOnVGZ54a37NEMr66TJ0glFslOJFuKWG6izg5DpKIUmDV9rRxjm47Q==" + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.10.tgz", + "integrity": "sha512-+6ibpv6jpkTNJS6yErQSEjbxCWf1/jMeUSlpSlUiTYf73LGR9riSRlIrL1+JEW0eEpb6MelQ04BIc38aj8GtxQ==" }, "@smithy/middleware-serde": { "version": "3.0.3", @@ -256,9 +256,9 @@ "integrity": "sha512-YvnElQy8HR4vDcAjoy7Xkx9YT8xZP4cBXcbJSgm/kxmiQu08DwUwj8rkGnyoJTpfl/3xYHH+d8zE+eHqoDCSdQ==" }, "@smithy/node-http-handler": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.1.2.tgz", - "integrity": "sha512-Td3rUNI7qqtoSLTsJBtsyfoG4cF/XMFmJr6Z2dX8QNzIi6tIW6YmuyFml8mJ2cNpyWNqITKbROMOFrvQjmsOvw==" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.1.3.tgz", + "integrity": "sha512-UiKZm8KHb/JeOPzHZtRUfyaRDO1KPKPpsd7iplhiwVGOeVdkiVJ5bVe7+NhWREMOKomrDIDdSZyglvMothLg0Q==" }, "@smithy/property-provider": { "version": "3.1.3", @@ -266,9 +266,9 @@ "integrity": "sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g==" }, "@smithy/protocol-http": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.0.3.tgz", - "integrity": "sha512-x5jmrCWwQlx+Zv4jAtc33ijJ+vqqYN+c/ZkrnpvEe/uDas7AT7A/4Rc2CdfxgWv4WFGmEqODIrrUToPN6DDkGw==" + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.0.4.tgz", + "integrity": "sha512-fAA2O4EFyNRyYdFLVIv5xMMeRb+3fRKc/Rt2flh5k831vLvUmNFXcydeg7V3UeEhGURJI4c1asmGJBjvmF6j8Q==" }, "@smithy/querystring-builder": { "version": "3.0.3", @@ -296,9 +296,9 @@ "integrity": "sha512-3BcPylEsYtD0esM4Hoyml/+s7WP2LFhcM3J2AGdcL2vx9O60TtfpDOL72gjb4lU8NeRPeKAwR77YNyyGvMbuEA==" }, "@smithy/smithy-client": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.7.tgz", - "integrity": "sha512-nZbJZB0XI3YnaFBWGDBr7kjaew6O0oNYNmopyIz6gKZEbxzrtH7rwvU1GcVxcSFoOwWecLJEe79fxEMljHopFQ==" + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.8.tgz", + "integrity": "sha512-nUNGCa0NgvtD0eM45732EBp1H9JQITChMBegGtPRhJD00v3hiFF6tibiOihcYwP5mbp9Kui+sOCl86rDT/Ew2w==" }, "@smithy/types": { "version": "3.3.0", @@ -336,14 +336,14 @@ "integrity": "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==" }, "@smithy/util-defaults-mode-browser": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.9.tgz", - "integrity": "sha512-WKPcElz92MAQG09miBdb0GxEH/MwD5GfE8g07WokITq5g6J1ROQfYCKC1wNnkqAGfrSywT7L0rdvvqlBplqiyA==" + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.10.tgz", + "integrity": "sha512-WgaNxh33md2zvlD+1TSceVmM7DIy7qYMtuhOat+HYoTntsg0QTbNvoB/5DRxEwSpN84zKf9O34yqzRRtxJZgFg==" }, "@smithy/util-defaults-mode-node": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.9.tgz", - "integrity": "sha512-dQLrUqFxqpf0GvEKEuFdgXcdZwz6oFm752h4d6C7lQz+RLddf761L2r7dSwGWzESMMB3wKj0jL+skRhEGlecjw==" + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.10.tgz", + "integrity": "sha512-3x/pcNIFyaAEQqXc3qnQsCFLlTz/Mwsfl9ciEPU56/Dk/g1kTFjkzyLbUNJaeOo5HT01VrpJBKrBuN94qbPm9A==" }, "@smithy/util-endpoints": { "version": "2.0.5", @@ -366,9 +366,9 @@ "integrity": "sha512-AFw+hjpbtVApzpNDhbjNG5NA3kyoMs7vx0gsgmlJF4s+yz1Zlepde7J58zpIRIsdjc+emhpAITxA88qLkPF26w==" }, "@smithy/util-stream": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.0.6.tgz", - "integrity": "sha512-w9i//7egejAIvplX821rPWWgaiY1dxsQUw0hXX7qwa/uZ9U3zplqTQ871jWadkcVB9gFDhkPWYVZf4yfFbZ0xA==" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.1.0.tgz", + "integrity": "sha512-QEMvyv58QIptWA8cpQPbHagJOAlrbCt3ueB9EShwdFfVMYAviXdVtksszQQq+o+dv5dalUMWUbUHUDSJgkF9xg==" }, "@smithy/util-uri-escape": { "version": "3.0.0", @@ -381,9 +381,9 @@ "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==" }, "@types/node": { - "version": "20.14.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", - "integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==" + "version": "20.14.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.11.tgz", + "integrity": "sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==" }, "@types/webidl-conversions": { "version": "7.0.3", diff --git a/packages/webapp/.npm/package/npm-shrinkwrap.json b/packages/webapp/.npm/package/npm-shrinkwrap.json index b72207874b..9d7195e99b 100644 --- a/packages/webapp/.npm/package/npm-shrinkwrap.json +++ b/packages/webapp/.npm/package/npm-shrinkwrap.json @@ -32,9 +32,9 @@ "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==" }, "@types/node": { - "version": "20.14.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", - "integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==" + "version": "20.14.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.11.tgz", + "integrity": "sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==" }, "@types/qs": { "version": "6.9.15", @@ -308,14 +308,21 @@ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" }, "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + "version": "1.53.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.53.0.tgz", + "integrity": "sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg==" }, "mime-types": { "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==" + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + } + } }, "ms": { "version": "2.0.0", From f169bc81bbde74cc6ebf0fe95b2fcf035f6ba5ee Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Fri, 19 Jul 2024 12:42:45 -0400 Subject: [PATCH 5/9] clean code --- packages/ddp-client/common/livedata_connection.js | 9 +-------- packages/ddp-server/livedata_server_tests.js | 3 +++ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/ddp-client/common/livedata_connection.js b/packages/ddp-client/common/livedata_connection.js index ac1d168420..b5c406c7a5 100644 --- a/packages/ddp-client/common/livedata_connection.js +++ b/packages/ddp-client/common/livedata_connection.js @@ -456,7 +456,7 @@ export class Connection { this.ready && this.readyDeps.changed(); }, stop() { - this.connection._sendQueued({ msg: 'unsub', id: id }); + this.connection._send({ msg: 'unsub', id: id }); this.remove(); if (callbacks.onStop) { @@ -1031,13 +1031,6 @@ export class Connection { this._stream.send(DDPCommon.stringifyDDP(obj)); } - // Always queues the call before sending the message - // Used, for example, on subscription.[id].stop() to make sure a "sub" message is always called before an "unsub" message - // https://github.com/meteor/meteor/issues/13212 - _sendQueued(obj) { - this._send(obj, true); - } - // We detected via DDP-level heartbeats that we've lost the // connection. Unlike `disconnect` or `close`, a lost connection // will be automatically retried. diff --git a/packages/ddp-server/livedata_server_tests.js b/packages/ddp-server/livedata_server_tests.js index cbc4e33b1b..87db540846 100644 --- a/packages/ddp-server/livedata_server_tests.js +++ b/packages/ddp-server/livedata_server_tests.js @@ -443,6 +443,9 @@ Tinytest.addAsync("livedata server - waiting for Promise", (test, onComplete) => }) ); +/** + * https://github.com/meteor/meteor/issues/13212 + */ Tinytest.addAsync('livedata server - publish cursor is properly awaited', async function (test) { const messages = [] From a45bb9eda51c154230290ddfc6cf6070efccf053 Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Fri, 19 Jul 2024 15:11:01 -0400 Subject: [PATCH 6/9] fix conflicting publication name --- packages/ddp-server/livedata_server_tests.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/ddp-server/livedata_server_tests.js b/packages/ddp-server/livedata_server_tests.js index 87db540846..57ed24acb4 100644 --- a/packages/ddp-server/livedata_server_tests.js +++ b/packages/ddp-server/livedata_server_tests.js @@ -471,16 +471,18 @@ Tinytest.addAsync('livedata server - publish cursor is properly awaited', async await coll.insertAsync({ _id: `item_${i}`, title: `Item #${i}` }); } - delete Meteor.server.publish_handlers['asyncPublishCursor']; + const publicationName = `publication_${Random.id()}` - Meteor.publish('asyncPublishCursor', async function (count) { + delete Meteor.server.publish_handlers[publicationName]; + + Meteor.publish(publicationName, async function (count) { return coll.find({}, { limit: count }); }); const reactiveVar = new ReactiveVar(1); const computation = Tracker.autorun(() => { - sub = clientConn.subscribe('asyncPublishCursor', reactiveVar.get()); + sub = clientConn.subscribe(publicationName, reactiveVar.get()); }); await sleep(100) From 6061c36bf8ca181a7a19893acfeb574fd682f53a Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Fri, 19 Jul 2024 15:19:59 -0400 Subject: [PATCH 7/9] remove test not needed --- .../test/livedata_connection_tests.js | 41 ------------------- 1 file changed, 41 deletions(-) diff --git a/packages/ddp-client/test/livedata_connection_tests.js b/packages/ddp-client/test/livedata_connection_tests.js index b2f5fd647a..1d20334e7b 100644 --- a/packages/ddp-client/test/livedata_connection_tests.js +++ b/packages/ddp-client/test/livedata_connection_tests.js @@ -2509,47 +2509,6 @@ if (Meteor.isClient) { test.equal((await coll.findOneAsync('aaa')).method, 222); test.equal((await coll.findOneAsync('aaa')).subscription, 112); }); - - Tinytest.addAsync( - "livedata connection - make sure the sub and unsub run in the correct order", - async function (test, onComplete) { - const stream = new StubStream(); - // Make sure to disable this flag so the subscribe and unsubscribe are queued - stream._neverQueued = false; - const conn = newConnection(stream); - - const sub = conn.subscribe("test_data"); - - // the subscribe message is still in the queue - test.isFalse(conn._readyToMigrate()); - test.length(stream.sent, 0); - - // unsubscribe - sub.stop(); - - // the queue still holds the data and no message arrived yet - test.isFalse(conn._readyToMigrate()); - test.length(stream.sent, 0); - - // waits until the queue is empty - await waitUntil(conn._readyToMigrate); - - // the first message is the sub message - let subMessage = JSON.parse(stream.sent.shift()); - test.equal(subMessage, { - msg: "sub", - name: "test_data", - params: [], - id: subMessage.id, - }); - test.length(stream.sent, 1); - - // the second message is the unsub - subMessage = JSON.parse(stream.sent.shift()); - test.equal(subMessage, { msg: "unsub", id: subMessage.id }); - test.length(stream.sent, 0); - } - ); } // XXX also test: From 5b9dfecf4114a502a2cf93d94a47004579d2b47f Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Mon, 22 Jul 2024 09:24:52 -0400 Subject: [PATCH 8/9] Revert "remove test not needed" This reverts commit 6061c36bf8ca181a7a19893acfeb574fd682f53a. --- .../test/livedata_connection_tests.js | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/packages/ddp-client/test/livedata_connection_tests.js b/packages/ddp-client/test/livedata_connection_tests.js index 1d20334e7b..b2f5fd647a 100644 --- a/packages/ddp-client/test/livedata_connection_tests.js +++ b/packages/ddp-client/test/livedata_connection_tests.js @@ -2509,6 +2509,47 @@ if (Meteor.isClient) { test.equal((await coll.findOneAsync('aaa')).method, 222); test.equal((await coll.findOneAsync('aaa')).subscription, 112); }); + + Tinytest.addAsync( + "livedata connection - make sure the sub and unsub run in the correct order", + async function (test, onComplete) { + const stream = new StubStream(); + // Make sure to disable this flag so the subscribe and unsubscribe are queued + stream._neverQueued = false; + const conn = newConnection(stream); + + const sub = conn.subscribe("test_data"); + + // the subscribe message is still in the queue + test.isFalse(conn._readyToMigrate()); + test.length(stream.sent, 0); + + // unsubscribe + sub.stop(); + + // the queue still holds the data and no message arrived yet + test.isFalse(conn._readyToMigrate()); + test.length(stream.sent, 0); + + // waits until the queue is empty + await waitUntil(conn._readyToMigrate); + + // the first message is the sub message + let subMessage = JSON.parse(stream.sent.shift()); + test.equal(subMessage, { + msg: "sub", + name: "test_data", + params: [], + id: subMessage.id, + }); + test.length(stream.sent, 1); + + // the second message is the unsub + subMessage = JSON.parse(stream.sent.shift()); + test.equal(subMessage, { msg: "unsub", id: subMessage.id }); + test.length(stream.sent, 0); + } + ); } // XXX also test: From 2db320a9fe6ac4a08d9924d63465a64f8c955a4d Mon Sep 17 00:00:00 2001 From: Leonardo Venturini Date: Mon, 22 Jul 2024 09:33:50 -0400 Subject: [PATCH 9/9] unsub still needs to be queued --- packages/ddp-client/common/livedata_connection.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/ddp-client/common/livedata_connection.js b/packages/ddp-client/common/livedata_connection.js index b5c406c7a5..f86d0971b3 100644 --- a/packages/ddp-client/common/livedata_connection.js +++ b/packages/ddp-client/common/livedata_connection.js @@ -456,7 +456,7 @@ export class Connection { this.ready && this.readyDeps.changed(); }, stop() { - this.connection._send({ msg: 'unsub', id: id }); + this.connection._sendQueued({ msg: 'unsub', id: id }); this.remove(); if (callbacks.onStop) { @@ -1031,6 +1031,16 @@ export class Connection { this._stream.send(DDPCommon.stringifyDDP(obj)); } + // Always queues the call before sending the message + // Used, for example, on subscription.[id].stop() to make sure a "sub" message is always called before an "unsub" message + // https://github.com/meteor/meteor/issues/13212 + // + // This is part of the actual fix for the rest check: + // https://github.com/meteor/meteor/pull/13236 + _sendQueued(obj) { + this._send(obj, true); + } + // We detected via DDP-level heartbeats that we've lost the // connection. Unlike `disconnect` or `close`, a lost connection // will be automatically retried.