Giter VIP home page Giter VIP logo

follow's Introduction

Follow: CouchDB changes and db updates notifier for NodeJS

build status

Follow (upper-case F) comes from an internal Iris Couch project used in production for over a year. It works in the browser (beta) and is available as an NPM module.

$ npm install follow

Example

This looks much like the request API.

var follow = require('follow');
follow("https://example.iriscouch.com/boogie", function(error, change) {
  if(!error) {
    console.log("Got change number " + change.seq + ": " + change.id);
  }
})

The error parameter to the callback will basically always be null.

Objective

The API must be very simple: notify me every time a change happens in the DB. Also, never fail.

If an error occurs, Follow will internally retry without notifying your code.

Specifically, this should be possible:

  1. Begin a changes feed. Get a couple of change callbacks
  2. Shut down CouchDB
  3. Go home. Have a nice weekend. Come back on Monday.
  4. Start CouchDB with a different IP address
  5. Make a couple of changes
  6. Update DNS so the domain points to the new IP
  7. Once DNS propagates, get a couple more change callbacks

Failure Mode

If CouchDB permanently crashes, there is an option of failure modes:

  • Default: Simply never call back with a change again
  • Optional: Specify an inactivity timeout. If no changes happen by the timeout, Follow will signal an error.

DB Updates

If the db url ends with /_db_updates, Follow will provide a _db_updates feed.

For each change, Follow will emit a change event containing:

  • type: created, updated or deleted.
  • db_name: Name of the database where the change occoured.
  • ok: Event operation status (boolean).

Note that this feature is available as of CouchDB 1.4.

Simple API: follow(options, callback)

The first argument is an options object. The only required option is db. Instead of an object, you can use a string to indicate the db value.

follow({db:"https://example.iriscouch.com/boogie", include_docs:true}, function(error, change) {
  if(!error) {
    console.log("Change " + change.seq + " has " + Object.keys(change.doc).length + " fields");
  }
})

All of the CouchDB _changes options are allowed. See http://guide.couchdb.org/draft/notifications.html.

  • db | Fully-qualified URL of a couch database. (Basic auth URLs are ok.)
  • since | The sequence number to start from. Use "now" to start from the latest change in the DB.
  • heartbeat | Milliseconds within which CouchDB must respond (default: 30000 or 30 seconds)
  • feed | Optional but only "continuous" is allowed
  • filter |
    • Either a path to design document filter, e.g. app/important
    • Or a Javascript function(doc, req) { ... } which should return true or false
  • query_params | Optional for use in with filter functions, passed as req.query to the filter function

Besides the CouchDB options, more are available:

  • headers | Object with HTTP headers to add to the request
  • inactivity_ms | Maximum time to wait between changes. Omitting this means no maximum.
  • max_retry_seconds | Maximum time to wait between retries (default: 360 seconds)
  • initial_retry_delay | Time to wait before the first retry, in milliseconds (default 1000 milliseconds)
  • response_grace_time | Extra time to wait before timing out, in milliseconds (default 5000 milliseconds)

Object API

The main API is a thin wrapper around the EventEmitter API.

var follow = require('follow');

var opts = {}; // Same options paramters as before
var feed = new follow.Feed(opts);

// You can also set values directly.
feed.db            = "http://example.iriscouch.com/boogie";
feed.since         = 3;
feed.heartbeat     = 30    * 1000
feed.inactivity_ms = 86400 * 1000;

feed.filter = function(doc, req) {
  // req.query is the parameters from the _changes request and also feed.query_params.
  console.log('Filtering for query: ' + JSON.stringify(req.query));

  if(doc.stinky || doc.ugly)
    return false;
  return true;
}

feed.on('change', function(change) {
  console.log('Doc ' + change.id + ' in change ' + change.seq + ' is neither stinky nor ugly.');
})

feed.on('error', function(er) {
  console.error('Since Follow always retries on errors, this must be serious');
  throw er;
})

feed.follow();

Pause and Resume

A Follow feed is a Node.js stream. If you get lots of changes and processing them takes a while, use .pause() and .resume() as needed. Pausing guarantees that no new events will fire. Resuming guarantees you'll pick up where you left off.

follow("https://example.iriscouch.com/boogie", function(error, change) {
  var feed = this

  if(change.seq == 1) {
    console.log('Uh oh. The first change takes 30 hours to process. Better pause.')
    feed.pause()
    setTimeout(function() { feed.resume() }, 30 * 60 * 60 * 1000)
  }

  // ... 30 hours with no events ...

  else
    console.log('No need to pause for normal change: ' + change.id)
})

Events

The feed object is an EventEmitter. There are a few ways to get a feed object:

  • Use the object API above
  • Use the return value of follow()
  • In the callback to follow(), the this variable is bound to the feed object.

Once you've got one, you can subscribe to these events:

  • start | Before any i/o occurs
  • confirm_request | function(req) | The database confirmation request is sent; passed the request object
  • confirm | function(db_obj) | The database is confirmed; passed the couch database object
  • change | function(change) | A change occured; passed the change object from CouchDB
  • catchup | function(seq_id) | The feed has caught up to the update_seq from the confirm step. Assuming no subsequent changes, you have seen all the data.
  • wait | Follow is idle, waiting for the next data chunk from CouchDB
  • timeout | function(info) | Follow did not receive a heartbeat from couch in time. The passed object has .elapsed_ms set to the elapsed time
  • retry | function(info) | A retry is scheduled (usually after a timeout or disconnection). The passed object has
    • .since the current sequence id
    • .after the milliseconds to wait before the request occurs (on an exponential fallback schedule)
    • .db the database url (scrubbed of basic auth credentials)
  • stop | The feed is stopping, because of an error, or because you called feed.stop()
  • error | function(err) | An error occurs

Error conditions

Follow is happy to retry over and over, for all eternity. It will only emit an error if it thinks your whole application might be in trouble.

  • DB confirmation failed: Follow confirms the DB with a preliminary query, which must reply properly.
  • DB is deleted: Even if it retried, subsequent sequence numbers would be meaningless to your code.
  • Your inactivity timer expired: This is a last-ditch way to detect possible errors. What if couch is sending heartbeats just fine, but nothing has changed for 24 hours? You know that for your app, 24 hours with no change is impossible. Maybe your filter has a bug? Maybe you queried the wrong DB? Whatever the reason, Follow will emit an error.
  • JSON parse error, which should be impossible from CouchDB
  • Invalid change object format, which should be impossible from CouchDB
  • Internal error, if the internal state seems wrong, e.g. cancelling a timeout that already expired, etc. Follow tries to fail early.

Tests

Follow uses node-tap. If you clone this Git repository, tap is included.

$ ./node_modules/.bin/tap test/*.js test/issues/*.js
ok test/couch.js ...................................... 11/11
ok test/follow.js ..................................... 69/69
ok test/issues.js ..................................... 44/44
ok test/stream.js ................................... 300/300
ok test/issues/10.js .................................. 11/11
total ............................................... 435/435

ok

License

Apache 2.0

follow's People

Contributors

3rd-eden avatar fb55 avatar jarrettmeyer avatar jcrugzz avatar jhs avatar jo avatar josip avatar kanongil avatar m64253 avatar max-mapper avatar mborho avatar narfdre avatar nprail avatar panuhorsmalahti avatar pdehaan avatar smithsz avatar stephen-bartell avatar tellnes avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

follow's Issues

It is safe to change feed.db after an error?

I want to use follow to listen changes from a couchdb server.
If that server dies, I want to follow the changes from a replica.

Code is something like this:

feed.on('retry', function(){                               
      feed.db = getTheNewServerToFollow();
});

Do you think it is correct? Do you think there is a better approach?

Fatal error: Error: Cannot find wait timer

(This bug is a note to self, may be opaque.)

Figured out how to reproduce this.

Start the distributor from scratch. Set the checkpoint high like 100k or 250k. After about 3 million docs, it will hit this pretty consistently.

TypeError: Cannot read property 'debug' of undefined at Feed.stop

If follow is being stopped, without being started first, it throws a fatal error:

/server/node_modules/nano/node_modules/follow/lib/feed.js:511
  self.log.debug('Stop')
          ^
TypeError: Cannot read property 'debug' of undefined
    at Feed.stop (/server/node_modules/nano/node_modules/follow/lib/feed.js:511:11)

I am using follow as part of nano, and this code seems to break the application

var feed = db.follow({since: 'now'});

var feed.on('change', function(change){
    console.log(change);
})

feed.stop();

Environment

$ npm -v
2.5.1

$ node -v
v0.12.0

$ couchdb -V
couchdb - Apache CouchDB 1.6.1

$ npm list nano       
โ””โ”€โ”€ [email protected]  extraneous

Duplicate change events after confirm timeout and restart

Here's the relevant code block to follow along.

In Feed.prototype.confirm, a request is made to check if the DB is reachable, and a timeout is set to detect a slow response from Couch. If the timeout is hit, the Feed is killed (self.die is called). But, the request object isn't destroyed. That means that if Couch responds after the timeout, the happy path callback db_response still gets called.

Normally, this isn't that noticeable, since the Feed object is dead and everything short-circuits. But, if the user called restart on the feed in response to the error, dead will be false, and the Feed ends up getting set up twice (once in response to the timed-out request, and once due to restart(). This results in every change event getting called twice.

The fix would seem to be adding destroy_req(req); here before dieing. I haven't figured out how to write a test for this though. Any ideas?

Another error question ...

I'm getting this error. I'm sure it's a problem in my code, but can someone explain what causes this error?

Error: Cannot find timeout timer during incoming data
    at Feed.on_couch_data (/opt/node/comps2/dev/node_modules/follow/feed.js:281:21)
    at Request.handle_confirmed_req_event (/opt/node/comps2/dev/node_modules/follow/feed.js:218:30)
    at Request.emit (events.js:64:17)
    at IncomingMessage.<anonymous> (/opt/node/comps2/dev/node_modules/request/main.js:290:55)
    at IncomingMessage.emit (events.js:64:17)
    at HTTPParser.onBody (http.js:119:42)
    at Socket.ondata (http.js:1227:22)
    at Socket._onReadable (net.js:683:27)
    at IOWatcher.onReadable [as callback] (net.js:177:10)

cannot read property 'socket' of undefined

I got this error today, now, I am running this in a tab on my laptop,
so I'm always switching between networks, and suspending, and unsuspending.

maybe that is the problem?

..../node_modules/follow/lib/feed.js:199
    feed_request.req.socket.emit('agentRemove')
                    ^
TypeError: Cannot read property 'socket' of undefined
    at Request.<anonymous> (/Users/dominictarr/.nave/installed/0.10.10/lib/node_modules/npmd/node_modules/level-couch-sync/node_modules/follow/lib/feed.js:199:21)
    at Request.EventEmitter.emit (events.js:95:17)
    at ClientRequest.<anonymous> (/Users/dominictarr/.nave/installed/0.10.10/lib/node_modules/npmd/node_modules/level-couch-sync/node_modules/follow/node_modules/request/main.js:427:14)
    at ClientRequest.g (events.js:175:14)
    at ClientRequest.EventEmitter.emit (events.js:95:17)
    at HTTPParser.parserOnIncomingClient [as onIncoming] (http.js:1663:21)
    at HTTPParser.parserOnHeadersComplete [as onHeadersComplete] (http.js:122:23)
    at Socket.socketOnData [as ondata] (http.js:1556:20)
    at TCP.onread (net.js:510:27)

Feature Request: negative since

It would be really nice if I could do:

var seq;

var f = follow(url)
f.since = -2
f.on('change', function (info) {
  seq = info.seq
})

So, -1 would actually be since=currentSequence. And -2 would be since (currentSequence - 1). That way, I could use -2 and as soon as the feed connects i'll get my global for the current sequence back.

Original data

When querying a view for changes it is often useful to get the full original set of view data before handling changes.

Would be nice if follow could handle this.

`follow` does not follow `skimdb.npmjs.com` to the end

I am currently writing a program to import the npm-registry into another database. I have the program that follow stops at change-number 375253 and does not receive any more data, but skimdb has over 500000 changes right now.
The issue can be reproduced with the following code snippet:

var follow = require('follow');

follow({db: "http://skimdb.npmjs.com/registry", since: 375250, include_docs: true}, function (error, change) {
    console.log("received seq " + change.seq + " from update stream");
});

I'm getting the output

received seq 375253 from update stream

followed by nothing but a waiting console (for days). However, if I go to https://skimdb.npmjs.com/registry/_changes?feed=continuous&since=375250&include_docs=true
I get many more updates.

It would by nice if you could have a look into it.

Failure mode not working

I've tested follow and its failure handling with the vanilla example.

var follow = require('follow');

follow({db:"http://127.0.0.1:5984/demo", inactivity_ms: (60 * 60 * 60 * 1000)}, function(error, change) {
  if(!error) {
    console.log("Got change number " + change.seq + ": " + change.id);
  }
});

Everything works fine until CouchDB is running, but when I shut down CouchDB follow raises:

events.js:72
        throw er; // Unhandled 'error' event
              ^
Error: connect ETIMEDOUT
    at errnoException (net.js:884:11)
    at Object.afterConnect [as oncomplete] (net.js:875:19)

It would be inevitable for my application that follow still waits until the server is available again.

CouchDB v1.3.0
node v0.10.8
follow v0.9.0

RFE: "seq_file" param to store change.seq and initial "since" value

I find myself doing this every time I use follow:

var seq = path.resolve(__dirname, 'sequence')
var since = readSeq(seq)

follow({
  db: myCouch,
  since: since
}, function(er, change) {
  if (er)
    throw er
  saveSeq(file, change.seq)
  // do stuff...
})

function readSeq(file) {
  try {
    return +fs.readFileSync(file, 'ascii') || 0
  } catch (er) {
    return 0
  }
}

var saving = {}
function saveSeq(file, seq) {
  if (saving[file])
    return
  saving[file] = true
  fs.writeFile(file, '' + seq + '\n', 'ascii', function(er) {
    saving[file] = false
  })
}

It's not that important to make sure that every sequence ID is saved, and of course, a lot in rapid succession will NOT be saved. But, I write follow scripts with the intent of them being crash-only and picking up where they leave off on a crash. Couch is great for this, and it'd be awesome if follow made it easier.

Ideal API:

follow({
  db: myCouch,
  seq_file: path.resolve(__dirname, 'sequence')
}, function(er, change) {
  // etc.
})

Bigcouch

I hate asking questions in the issues tab but I was wondering if follow was tested with bigcouch? I am getting some weird results when I try to follow my cloudant db.

Multiple databases

How would you go about creating a node app that could follow multiple databases in one process?

Check for dead on confirm_request response error

In case the confirm_request response comes after the feed was stopped and the database was deleted a Bad DB response will rise.

This is unexpected because the feed has already been stopped.

Calling stop() from a change handler leaks a timer

The problem:

  1. Data arrives, the data handler runs
  2. A Feed decides a change happened
  3. It fires a "change" event
  4. The handler calls .die()
  5. The die code cleans up stuff
  6. The stack unwinds and we realize we are still in the data handler from step 1
  7. That data handler calls self.wait() which starts a timer, so Node can't exit

timeOut objects not cleared when using trycatch > 1.5.11 / hookit > 0.1.1

Hello,

I am not sure if that issue should be submitted here, but as I have spent over a day trying to figure out what my bug was, I think it at least deserved to be documented. :)

So, I use follow 0.12.1 for tracking changes. I am also using trycatch, which depends on hookit. After I updated from trycatch 1.5.11 to 1.5.19, follow suddenly stopped working, always breaking with "Timeout confirming database".

I figured out that a timeOut object was never cleared, because the setTimeOut was returning undefined. Further analysis showed that trycatch recently upgraded the hookit version, which seems to break the setTimeOut function used in follow.

Downgrading to trycatch 1.5.11 and enforcing hookit to 0.1.1 seems to do the trick for now.

Error when db is deleted/recreated

Currently Follow will stop if the db being followed is deleted, or recreated:

Change has no .seq field: {"last_seq":7}

This could be problematic but I guess Follow should be aware of such situations and restart the process without raising an exception (or perhaps make this configurable).

tests are failing

Hi,
I am packaging this module in Fedora linux. I am running tests in rpm specfile as
tap test/couch.js

TypeError: Cannot read property 'body' of undefined
at Request._callback (/home/parag/rpmbuild/BUILD/package/test/couch.js:57:14)
at self.callback (/usr/lib/node_modules/request/index.js:148:22)
at Request.emit (events.js:95:17)
at ClientRequest.self.clientErrorHandler (/usr/lib/node_modules/request/index.js:257:10)
at ClientRequest.emit (events.js:95:17)
at Socket.socketErrorListener (http.js:1551:9)
at Socket.emit (events.js:95:17)
at net.js:440:14
at process._tickCallback (node.js:419:13)

not ok test/couch.js .................................... 0/1
Command: "node" "couch.js"
TAP version 13
not ok 1 test/couch.js
---
exit: 8
stderr: |
TypeError: Cannot read property 'body' of undefined
at Request._callback (/home/parag/rpmbuild/BUILD/package/test/couch.js:57:14)
at self.callback (/usr/lib/node_modules/request/index.js:148:22)
at Request.emit (events.js:95:17)
at ClientRequest.self.clientErrorHandler (/usr/lib/node_modules/request/index.js:257:10)
at ClientRequest.emit (events.js:95:17)
at Socket.socketErrorListener (http.js:1551:9)
at Socket.emit (events.js:95:17)
at net.js:440:14
at process._tickCallback (node.js:419:13)
command: "node" "couch.js"
...

1..1
# tests 1
# fail  1

TypeError: Cannot read property 'body' of undefined
at Request._callback (/home/parag/rpmbuild/BUILD/package/test/couch.js:57:14)
at self.callback (/usr/lib/node_modules/request/index.js:148:22)
at Request.emit (events.js:95:17)
at ClientRequest.self.clientErrorHandler (/usr/lib/node_modules/request/index.js:257:10)
at ClientRequest.emit (events.js:95:17)
at Socket.socketErrorListener (http.js:1551:9)
at Socket.emit (events.js:95:17)
at net.js:440:14
at process._tickCallback (node.js:419:13)

What am I missing? This error is same for other test files also.

Thanks.

Inactivity timeout sometimes triggers immediately

When setting timeout_ms = 60000 and since = 0, the timeout sometimes immediately (on the same second), even if there are changes. This doesn't happen all the time, and I can't manage to reproduce it consistently except on a running system where after ~1day it will consistantly fail.

The way I use it:

  • Create a feed with the specified parameters.
  • Define on_timeout handler which calls removeAllListeners and stop (and deletes the feed).
  • Start the feed.
  • Later, after a (real) timeout, repeat the process.

At some point, the timeout is triggered always immediately. Restarting the process fixes it.

DB instance_start_time check is unnecessary

follow requires the JSON response from GET /db to contain an instance_start_time property, but it never uses the value of that property. Here's the check.

This makes follow incompatible with the Couchbase Sync Gateway (and Couchbase Lite when its listener/server plugin is used), because those implementations don't happen to include such a key in that response. Mostly because there is no explicit standard, and it hadn't seemed important enough to provide that information.

I can and will update our Couchbase codebases to return this key and make them compatible, but it also seems better for follow not to require a key that it doesn't otherwise use.

Abandoned?

Last commit was about one year. Is this project abandoned?

JSON parse issue

Fairly certain CouchDB isn't sending invalid JSON, just that the line parser might be fucked up in follow.

SyntaxError: Unexpected token H
    at Object.parse (native)
    at Request.db_response [as _callback] (/node_modules/follow/lib/feed.js:122:17)
    at Request.self.callback (/node_modules/request/index.js:142:22)
    at Request.EventEmitter.emit (events.js:98:17)
    at Request.<anonymous> (/node_modules/request/index.js:856:14)
    at Request.EventEmitter.emit (events.js:117:20)
    at IncomingMessage.<anonymous> (/node_modules/request/index.js:808:12)
    at IncomingMessage.EventEmitter.emit (events.js:117:20)
    at _stream_readable.js:870:14
    at process._tickDomainCallback (node.js:459:13)

Auto-scalling multiple instances

Hi follows,

There is a way to scalling a node app with follow? If i had 2 instances follow the same CouchDB database whats will happen? Its just a newbie doubt, i dont find anything talking about that.

Cheers fellows

Support _db_updates

Introduced in 1.4, _db_updates lets you follow database events.

The API is almost the same as the _changes API and I think it makes sense for Follow to also support db updates feeds.

Error: Cannot find wait timer

Occasionally this happens:

Error: Cannot find wait timer
    at Feed.got_activity (/home/node/node_modules/npm-fullfat-registry/node_mo
dules/follow/lib/feed.js:355:21)
    at Feed.on_couch_data (/home/node/node_modules/npm-fullfat-registry/node_m
odules/follow/lib/feed.js:412:8)
    at Changes.handle_confirmed_req_event (/home/node/node_modules/npm-fullfat-registry/node_modules/follow/lib/feed.js:308:30)
    at Changes.EventEmitter.emit (events.js:95:17)
    at Changes.emit_changes (/home/node/node_modules/npm-fullfat-registry/node_modules/follow/lib/stream.js:223:12)
    at Changes.write_continuous (/home/node/node_modules/npm-fullfat-registry/node_modules/follow/lib/stream.js:176:8)
    at Changes.write (/home/node/node_modules/npm-fullfat-registry/node_modules/follow/lib/stream.js:124:17)
    at Request.ondata (stream.js:51:26)
    at Request.EventEmitter.emit (events.js:95:17)
    at IncomingMessage.<anonymous> (/home/node/node_modules/npm-fullfat registry/node_modules/follow/node_modules/request/request.js:840:12)

??

SSL

I'm using nano to access couchdb, and my couchdb installation use https with a non-verified SSL. In "nano" I can change the request options through "request_defaults". I couldn't find how to do it in "follow", maybe I missed somewhere in documentation. I keep getting DEPTH_ZERO_SELF_SIGNED_CERT error.

I've tried to change line 111 follow.js to:

var req = request({'uri':self.db, 'headers':headers, 'strictSSL':false}, db_response)

But it still returns the same error. I guess there is another request object somewhere that I'm missing or I'm misunderstanding the error.

I dont know if post an issue for that is the best way to ask those questions. If not, I'm sorry please tell me the best way to do it. I couldnt find nothing on google.

Thanks

Crash when Follow tries to crash

.../node_modules/follow/lib/feed.js:572
  return self.die(new Error('Req ' + self.pending.request.id() + ' made no cha
                                                          ^TypeError: Cannot call method 'id' of null
    at Feed.on_inactivity (.../node_modules/follow/lib/feed.js:572:59)
    at Object._onTimeout (.../node_modules/follow/lib/feed.js:559:58)
    at Timer.ontimeout (timers.js:84:39)

Feed that starts at "now" cannot be stopped

I want to stop the follow feed once it has caught up with the database. Unfortunately, if the feed's since is the db's current seq then a _changes request is left hanging and the JS process runs indefinitely.

Here's example code that demonstrates the issue:

var follow = require("follow");

var db = process.argv[2];
var since = process.argv.length > 3 ? parseInt(process.argv[3]) : "now";

var feed = new follow.Feed({db: db, since: since});
feed.on("change", function(change) {
    console.log("change:", change.seq);
});
feed.on("catchup", function() {
    console.log("catchup");
    feed.stop();
});
feed.on("stop", function(err) {
    console.log("stop:", err);
    setTimeout(function() {
        var handles = process._getActiveHandles();
        handles.forEach(function(handle) {
            console.log("******************************");
            console.log(handle);
        });
        console.log(handles.length);
    }, 1000);
});
feed.follow();

The JS process will hang unless a value for since is provided that's older that the db's current seq. When it hangs the request to the _changes feed is visible in the dump of active handles (the timeout just gives things a bit of time to settle down).

exception in feed.js

I got an exception in line 326 of feed.js ...

self.log.warn('Closing req ' + self.pending.request.id() + ' for timeout after ' + elapsed_ms + 'ms; heartbeat=' + self.heartbeat);

self.pending.request was null so I got ...

[{"stack":"TypeError: Cannot call method 'id' of null
    at Feed.on_timeout (/opt/node/comps2/dev/node_modules/follow/feed.js:326:55)
at Object._onTimeout (/opt/node/comps2/dev/node_modules/follow/feed.js:274:58)
at Timer.callback (timers.js:83:39)","arguments":["id",null],"type":"non_object_property_call","message":"Cannot call method 'id' of    null"}]

This is in production code but my code could be bad of course.

process crash when using pause() resume() for large database

On a db of ~1.1 million records, i call follow on it like this:

follow({db:"https://example.iriscouch.com/bigdatabase", include_docs:true}, function(error, change) {
    var feed = this
    feed.pause()
    setTimeout(function() { feed.resume() }, 500)
})

Memory climbs rapidly until a GC error crashes process at around 1.5GB of memory usage.

Using node debugger, heap snapshot reveals json strings of changes (which is the entire doc since i'm passing include_docs: true) is what is accounting for the high mem usage and eventual crash of process.

Is this what is known as backpressure ? If i do away with the pause() resume() the issue goes away, but i need to be able to pause() resume() to do some async stuff with each change in sequence.

Just wondering if anyone can explain my issue and/or potential solutions. Thanks

Now way to get the whole doc

Hello,

I tried the following code :


var app = require('express')(),
server = require('http').createServer(app),
io = require('socket.io').listen(server);

server.listen(8888);

var follow = require('follow');
follow({db:"http://localhost:5984/baseball/", include_docs:true}, function(error, change) {
if(!error) {
console.log("Got change number " + change.seq + ": ");
io.sockets.on('connection', function (socket) {

    socket.emit('news', change);

});
}
})


My doc is of the form :

{
"_id": "3a926675dbac89820e2f8b3746001003",
"_rev": "28-57309ea14f606e494dc94cd0816f8d99",
"re": "hgypmp",
"mim": "ghj"
}

How can I pass the value of re and mim to the browser ?
I saw that I can grab the key but no way I can get change.re or change.mim.

Any idea ?

Thanks !

Cannot build for browser

Thanks for this great Node listener!

In the readme you tell about (beta) browser support. I think it would be great to have a solid _changes follower from the browser. Bad thing is I could not build the project using rake.

rake aborted!
Don't know how to build task 'feed.js'
/Users/sjoerd/.rvm/gems/ruby-1.9.3-p194/bin/ruby_noexec_wrapper:14:in `eval'
/Users/sjoerd/.rvm/gems/ruby-1.9.3-p194/bin/ruby_noexec_wrapper:14:in `<main>'
Tasks: TOP => default => export
(See full trace by running task with --trace)

Am I doing something wrong, or is follow not browser compatible anymore?

Retry doesn't do exponential fallback for views

According to the documentation retry uses a "exponential fallback schedule", but I'm seeing that the delay between retries stays at always 1000ms. The reason is that if CouchDB returns a 200 with a null body (as it does for me), it's considered what the debug message calls a 'Good response', which restarts the retry delay. And because it's not really a good response, it retries anyway (as it should). This happens whenever I follow a view which does not exist.

If I change it so that the delay is not reset on an empty body it just retries continuously without waiting until it reaches the maximum.

Thoughts?

Database deleted after change

I'm currently using follow through the nano api to listen on the changes feed of a cloudant database. I've noticed an issue where follow will kill itself with the following error

Error: Database deleted after change: 89799568-g1AAAAJHeJzLYWBg4MhgTmGQT0lKzi9KdUhJMjTWy0zKNTAw10vOyS9NScwr0ctLLckBKmRKZEiS____f1YGUxLDamvbXKAYu6GpYbKRsTnIDDm4GeY4jUhSAJJJ9nBToprBpphZJBuZWCYT7ZIkB5Ax8XBjPE6AjTExSTS2NEsj3pgEkDH1cGPsfSDGWJglJ1ukEeunPBYgydAApIAGzYeYFP0D4q9EQ2NDS3M0BxkRMGoBxKj9EKNsjoCNsjAwTEyxtCTNUQcgJt2HmBToCTbJINnINMUwBdUkMwImPYCYBA0o4-1gkyyT09IsUiyzAH6UsGc
    at Feed.on_couch_data (/Users/csaroff/CloudOE/segment/loginlistener/node_modules/nano/node_modules/follow/lib/feed.js:440:18)
    at Changes.handle_confirmed_req_event (/Users/csaroff/CloudOE/segment/loginlistener/node_modules/nano/node_modules/follow/lib/feed.js:325:30)
    at Changes.emit (events.js:107:17)
    at Changes.emit_changes (/Users/csaroff/CloudOE/segment/loginlistener/node_modules/nano/node_modules/follow/lib/stream.js:223:12)
    at Changes.write_continuous (/Users/csaroff/CloudOE/segment/loginlistener/node_modules/nano/node_modules/follow/lib/stream.js:176:8)
    at Changes.write (/Users/csaroff/CloudOE/segment/loginlistener/node_modules/nano/node_modules/follow/lib/stream.js:124:17)
    at Request.ondata (stream.js:51:26)
    at Request.emit (events.js:107:17)
    at IncomingMessage.<anonymous> (/Users/csaroff/CloudOE/segment/loginlistener/node_modules/nano/node_modules/follow/node_modules/request/request.js:1164:12)
    at IncomingMessage.emit (events.js:107:17)
    at readableAddChunk (_stream_readable.js:163:16)
    at IncomingMessage.Readable.push (_stream_readable.js:126:10)
    at HTTPParser.parserOnBody (_http_common.js:132:22)
    at TLSSocket.socketOnData (_http_client.js:317:20)
    at TLSSocket.emit (events.js:107:17)
    at readableAddChunk (_stream_readable.js:163:16)
    at TLSSocket.Readable.push (_stream_readable.js:126:10)
    at TCP.onread (net.js:538:20)

It seems that the issue is being caused because cloudant is sending a last_seq in a continuous change which follow incorrectly interprets as a dropped database.

last_seq can occur on cloudant timeouts. I propose that connection restart be attempted instead of throwing an error and killing the connection.

Proposal: inactivity_ms does not perform as expected/documented, let's fix that.

According to the documentation, when providing a value for inactivity_ms, "If no changes happen by the timeout, Follow will signal an error." But it actually calls on_inactivity, which restarts the feed (see https://github.com/iriscouch/follow/blob/master/lib/feed.js#L624-L637).

In some cases it is not desirable to automatically retry the feed. In my case, for example, I have a large number of databases which I want to stop following once they have been inactive for a while.

Furthemore, the documented behaviour (emiting an error) seems somewhat confusing: the fact that there haven't been changes on a database should not be an error.

Instead, I would propose the following:

  • Emit a 'timeout' signal when the timeout expires.
  • Add a setting retry_after_timeout (default true), which determines whether the feed should be retried after a timeout.

This would allow users to indicate what they want Follow to do when there is a timeout, without breaking backwards compatibility.

If you are okay with this proposal, I'll implement it and send a PR.

Update engines directive in package.json

Any reason why the package.json engines directive cannot be updated for Node 4.x to prevent the npm warning: [email protected]: wanted: {"node":"0.12.x || 0.10.x || 0.8.x"} (current: {"node":"4.2.0","npm":"2.14.7"})?

Obviously this assumes that testing on Node 4.x proves compatibility.

Use cookie auth with nano and follow

I'm using nano to talk to an authenticated couchdb instance, and hoping to use the awesome follow features. Is there any workflow that allows cookie auth (supported by nano) to be used for follow requests? I can't see any way to make this work, other than leaving the credentials in the connection string, which would then get passed into follow.

Cheers,

Eddie

Crash in feed.js on_timeout

I am using nano to follow a cloudant db and my code crashes repeatedly in the follow module.
File: lib/feed.js

This line of code causes the error. Seems like self.pending.request is null.
self.emit('timeout', {elapsed_ms:elapsed_ms, heartbeat:self.heartbeat, id:self.pending.request.id()});

TypeError: Cannot call method 'id' of null
at Feed.on_timeout (C:\workspace\myApp\node_modules\nano\node_modules\follow\lib\feed.js:46
3:98)

Could this be caused by wrong usage or is it a bug within the follow module?

Vanilla example fails

npm version 0.7.0
couchdb 1.1.0

changes_stream.log.setLevel(self.log.level.levelStr)
                                          ^

TypeError: Cannot read property 'levelStr' of undefined
at Request.on_feed_response as onResponse
at ClientRequest. (/home/william/projects/tmp/node_modules/follow/node_modules/request/main.js:430:16)
at ClientRequest.emit (events.js:67:17)
at HTTPParser.onIncoming (http.js:1225:11)
at HTTPParser.onHeadersComplete (http.js:102:31)
at Socket.ondata (http.js:1124:24)
at TCP.onread (net.js:336:27)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.