Jesse
Jesse

Reputation: 10466

close RethinkDB changefeed before changed

I can't seem to find any info in the rethinkdb docs on how you might stop a changefeed before the first change is fired. Here's the problem that makes this necessary:

A client connects to the server via a socket, which begins a changefeed, something like this:

var changeCursors = {};
db('app').table('things').changes().run(cursor, function(err, cursor) {
  // do something when changed
  changeCursors[user.id] = cursor
})

// later, when the user disconnects
changeCursors[user.id].close()

When the first change is dispatched, I can assign the cursor to a variable in memory, and if the client disconnects, close this cursor.

However, what if the user disconnects before the first change?

As far as I can tell, rethink doesn't support dispatching an initial state to the feed, so the cursor will only be available after a change. However, if the user disconnects, changeCursors[user.id] is undefined, and the changefeed stays open forever.

This can be solved by checking a state object inside the changefeed and just closing the feed after the first change, but in theory if there are no changes and many connected clients, we can potentially open many cursors that will eat memory for no reason (they'll be closed as soon as they update).

Is there a way to get the cursor from a changefeed without the run callback being executed? Alternatively, is there a way to force rethink to perform an initial state update to the run callback?

Upvotes: 2

Views: 1027

Answers (1)

mlucy
mlucy

Reputation: 5289

You'd have this problem even if the server responded immediately, because the user might disconnect after you've sent the query to the server and before the response has made it back. Unfortunately we can't create the cursor before sending the query to the server because in the general case figuring out the return type of the query is sort of hard, so we don't put that logic in the clients.

I think the best option is what you described, where if the cursor hasn't been returned yet you set a flag and close it inside the callback. You might be able to make the logic cleaner using promises.

I wouldn't worry about memory usage unless you're sure it's a problem; if some portion of a second passes without a change, we return a cursor with no initial values to the client, so your memory use in the case of a lot of users opening and then immediately closing connections will be proportional to how many users can do that in that portion of a second. If that portion of a second is too long for you, you can configure it to be smaller with the optargs to run (http://rethinkdb.com/api/javascript/run/). (I would just set firstBatchScaledownFactor to be higher in your case.)

Upvotes: 1

Related Questions