Stuck on a ridiculously simple thing: How to run a function every couple of seconds?

This is the function I want to execute every couple of seconds:

if (Meteor.isServer) {
function download() {
  console.log("Entering");
  var Twit = Meteor.npmRequire('twit');

  var T = new Twit({
    consumer_key:         'x', // API key
    consumer_secret:      'x', // API secret
    access_token:         'x-x',
    access_token_secret:  'x'
  });

  T.get('search/tweets',
    {
      q: 'banana',
      count: 100
    },
    function(err, data, response) {
      for (var i = 0; i < data.statuses.length; i++) {
        Tweets.insert({ createdAt: new Date(), twitter_id: data.statuses[i].id_str });
      }
    }
  );
}
}

I’ve thrown everything but the kitchen sink at this for the past 4 hours and I’m stuck badly. I don’t understand why it’s so hard to accomplish this in Meteor, I must be doing something wrong.

My latest error is:

Error: Meteor code must always run within a Fiber. Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment.


So, if I have this function: How can I run it every 5 seconds? What’s the easiest way to do this?

Have you tried doing exactly what that error message is telling you? Namely, wrap that download function in Meteor.bindEnvironment?

setInterval(Meteor.bindEnvironment(download), 5000)

And you have to wrap the async callback function that you pass to T.get() in Meteor.bindEnvironment as well. The idea is that you have to do that for every bit of code that you make run outside of regular Meteor-called functions (Meteor methods, publications, other regular server code), so basically anything that runs async.

And minor nitpick: Put calls to require/npmRequire outside of code that executes more than once. Import and require statements should go at the top of a file for more clarity and performance (executing only once).

1 Like

Same deal, unless I have to wrap the T.get callback in it’s owner Meteor.bindEnvironment as well. Is that true?

Like the error says the callback is what you need to wrap. Also use Meteor.setInterval.

2 Likes

So yes, that’s what the error tells you.

Thanks guys! :muscle:

@sergiotapia could you post the fixed code? This might be a nice example for the community.

You should use Meteor.wrapAsync for your T.get function since it automatically wraps it in a Fiber. Look at this example:

If your NPM package’s function callback signature is (err, result), you can literally just do:

import funcAsync from 'your-async-npm-pkg';
var funcSync = Meteor.wrapAsync(funcAsync);

However, because the T.get function’s callback has a different signature you would use the example I linked to.

I also just updated that thread, adding an async/await example. That should work fine in Meteor 1.3 as async/await will handle the Fibers stuff behind the scenes while on the server-side.

1 Like