Mike Graf
Mike Graf

Reputation: 5317

How to debug slow meteor methods?

A number of my meteor methods have mysteriously slowed down recently. Whereas they used to be quite snappy, many are taking 10 or so seconds.

Things not causing the slowdown:

I did debugging by using console.time() / console.timeEnd() on both the server and client side. The server side code takes about .3 seconds to run, but the client doesnt get the callback until about 11 seconds after the meteor.call() ...

This is the server method:

function cancelSomething(somethingId, reason) {
  console.time('cancelSomething method');
  check(somethingId, String);
  check(reason, String);

  if (!AuthChecks()))
    throw new Meteor.Error(401, 'Not Authorized');

  var something = MySomethings.findOne({'_id': somethingId});
  if (!something)
    throw new Meteor.Error(404, 'Something not found');

  var returnVal = SomethingService.cancel(something, reason);
  console.timeEnd('cancelSomething method'); // <--- prints "cancelSomething 350ms" or there abouts
  return returnVal;
}

clientSide:

  console.time('meteorCall');
  Meteor.call('cancelSomething', this._id, reason, function(err) {
    if (err) {
        console.log('an error occurred', err);
    }
    console.timeEnd('meteorCall'); // <--- prints "meteorCall 11500" or so
  });

EDIT: I have noticed there is some correlation with the quantity of docs within the "somethings" in the db. w/ 500 documents it takes about 1 second to receive the return on the client, with 5000 it takes about 8.5 seconds ...

Upvotes: 4

Views: 1205

Answers (1)

David Weldon
David Weldon

Reputation: 64342

Interesting. I think this one is hard to answer without knowing more about your app, but I have some suggestions that could help steer you in the right direction.

blocking

If we can assume that the timers are working properly, what could be happening is that the server is unable to begin execution of the method because another method call by the same client is already in progress. Have a look at unblock in the docs. The answer may be as simple as putting a this.unblock at the top of one of your methods.

syncing

If SomethingService.cancel does something which results in a lot of DDP traffic, that could tie up the client for a while and make it unable to execute your callback. For example if it:

  • modified or created a lot of documents which then had to be synced to the client
  • indirectly caused an expensive subscription to be rerun (my money is on this one)

Updated Answer

It seems the problem had to to with a call to observe, which makes a lot of sense given your high CPU load. Frankly, it's a little silly that I didn't suggest this because I have already answered a similar question here. If you want to try to keep the observe, here are some additional suggestions:

  • Use oplog tailing.
  • Try to narrow the scope of the observe as much as possible using selectors which are currently supported by the oplog observe driver. The supported selectors should improve at or before meteor 1.0.
  • Limit the fields to only those you need.
  • Check that oplog tailing is working by adding the facts package.

Upvotes: 4

Related Questions