-
Notifications
You must be signed in to change notification settings - Fork 445
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
✨ Add multi channel query subscription. #587
Conversation
lib/backend.js
Outdated
stream.destroy(); | ||
return callback(err); | ||
|
||
var channels = [request.channel]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should reorganise this a bit to log a deprecation warning for using request.channel
(ie it should be unset by default, and if a consumer actively sets it, then we should log a warning).
lib/backend.js
Outdated
backend.emit('timing', 'querySubscribe.initial', Date.now() - start, request); | ||
callback(null, queryEmitter, snapshots, extra); | ||
// Issue query on db to get our initial results | ||
backend._query(agent, request, function(err, snapshots, extra) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be nice if we could avoid hitting the DB with the same query multiple times
f1b6a11
to
cec9ac9
Compare
a12d3af
to
f27470c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comments from last week, forgot to publish 😅
f27470c
to
bb5bcab
Compare
test/client/query-subscribe.js
Outdated
}); | ||
}); | ||
|
||
it('creating a document updates a subscribed query', function(done) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since many of these tests are identical to above, let's either make a shared function with the shared tests invoked for each case, or use a for-each. That reduces test maintenance.
test/client/query-subscribe.js
Outdated
@@ -592,5 +592,769 @@ module.exports = function(options) { | |||
}); | |||
}); | |||
}); | |||
|
|||
describe('custom channels', function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Alec) Let's add a test around making sure things still work (no duplicate doc events) if multiple channels match, if debounce is disabled by the sharedb user.
c5dd7d7
to
2ca6a2f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alec notes that we don't have a "golden path" test case on the expected use of this new featurre.
Something like:
- Notes query on
{ users: { $in: { ['user-1', 'user2'] } } }
, with those channels - One op on solely channel 'user-1', another op solely on 'user-2' channel
- Make sure query receives both updates
lib/backend.js
Outdated
var channels = request.channels; | ||
|
||
if (request.channel) { | ||
logger.warn('[DEPRECATED] Do no use channel for query, use channels instead.'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Suggested update to be clearer, since this only shows the log line -
[DEPRECATED] "query" middleware's context.channel is deprecated, use context.channels instead.
- Also update query middleware documentation - https://share.github.io/sharedb/middleware/actions#query
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed
test/client/query-subscribe.js
Outdated
} | ||
], function(err) { | ||
|
||
it('creating an additional document updates a subscribed query', function(done) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can get rid of this second one, apparently we've had this exact duplicate copy for a long time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
query.on('error', done); | ||
query.on('insert', function() { | ||
count++; | ||
if (count === 3) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alec - let's add a > 3
condition that calls done with error, so it will catch cases where duplicate causes it to go above 3
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed
8d2e1fe
to
98a00be
Compare
Added new test sharedb/test/client/query-subscribe.js Lines 17 to 88 in 98a00be
|
@ericyhwang @alecgibson I manage to get duplicated results with multiple channels. https://github.com/share/sharedb/actions/runs/4184518977/jobs/7250274650 sharedb/test/client/query-subscribe.js Lines 120 to 147 in 98a00be
Although it is quite difficult to get it in test, even if the test passes we cannot be 100% sure this multi channel connection works. Maybe just test like 100 messages to ensure non of them are duplicated. 🤷 I wonder if we should force |
@dawidreedsy I'm not sure that that's a duplicate message; just looks like the inserts were reported in a different order? I'm not sure if a query's sort order is well-defined...? Or does it depend on the query? Maybe we need to fix the order? |
@alecgibson Yeah sorry I missed the |
98a00be
to
9639e94
Compare
960ee7e
to
8cf4f10
Compare
8cf4f10
to
3fde903
Compare
lib/error.js
Outdated
@@ -68,7 +68,8 @@ ShareDBError.CODES = { | |||
ERR_SUBMIT_TRANSFORM_OPS_NOT_FOUND: 'ERR_SUBMIT_TRANSFORM_OPS_NOT_FOUND', | |||
ERR_TYPE_CANNOT_BE_PROJECTED: 'ERR_TYPE_CANNOT_BE_PROJECTED', | |||
ERR_TYPE_DOES_NOT_SUPPORT_PRESENCE: 'ERR_TYPE_DOES_NOT_SUPPORT_PRESENCE', | |||
ERR_UNKNOWN_ERROR: 'ERR_UNKNOWN_ERROR' | |||
ERR_UNKNOWN_ERROR: 'ERR_UNKNOWN_ERROR', | |||
ERR_MISSING_QUERY_CHANNEL: 'ERR_MISSING_QUERY_CHANNEL' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All of our other error codes generally have the format ERR_<THING>_<DESCRIPTION>
, so let's try to stick to that:
ERR_MISSING_QUERY_CHANNEL: 'ERR_MISSING_QUERY_CHANNEL' | |
ERR_QUERY_CHANNEL_MISSING: 'ERR_MISSING_QUERY_CHANNEL' |
Also can you please alphabetise
ead4de4
to
40f1f26
Compare
}); | ||
}); | ||
it('returns pubSub error if fails to subscribe to channel', function(done) { | ||
sinon.stub(this.backend.pubsub, 'subscribe').callsFake(function(_channel, callback) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add an afterEach
with sinon.restore
in test/setup.js just to be clean about the tear-down, though Alec points out we create a new backend each test case so it's fine in this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added
test/client/query-subscribe.js
Outdated
}); | ||
|
||
it('pollInterval captures additional unpublished creates', function(done) { | ||
this.timeout(4000); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's use sinon fake timers here, to avoid artificially lengthening the test case.
Will have to advance time at least 3 times, we think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added fakeTimers
40f1f26
to
e29155e
Compare
b81b81e
to
2373ae5
Compare
@dawidreedsy I've released the |
It may be worth considering dropping support for Node 14, as it's nearing EOL according to https://github.com/nodejs/release#release-schedule |
2373ae5
to
d804bd2
Compare
At the moment we can only specify one channel the specific query, would be able to listen to, as per docs: ```javascript backend.use('query', (context, next) => { // Set our query to only listen for changes on our user-specific channel context.channel = userChannel(context) next() }) ``` However let's imagine the situation where the user wants to query all the posts, the where posted by him and all his friends. Now we would need new query every for friend separately to make sure the proper scalability is preserved and we do not receive all the changes to posts collection. This change allows to listen for multiple channels, so if we want to query all user friends posts. We can do it by this: ```javascript backend.use('query', (context, next) => { // Set our query to only listen for changes on our user-specific channel context.channels = [userChannel(context), friendChannel(context))] next() }) ``` Now this query would only listen to all the changes that were made to the user posts and his friends.
d804bd2
to
628de99
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚀
At the moment we can only specify one channel the specific query, would be able to listen to, as per docs:
However let's imagine the situation where the user wants to query all the posts, the where posted by him and all his friends. Now we would need new query every for friend separately to make sure the proper scalability is preserved and we do not receive all the changes to posts collection. This change allows to listen for multiple channels, so if we want to query all user friends posts. We can do it by this:
Now this query would only listen to all the changes that were made to the user posts and his friends.