8

I'm a newbie with Meteor and I'm trying to get an async data from the Heroku API.

Server side code:

heroku = Meteor.require("heroku");

Meteor.methods({
    'getHeroku': function getHeroku(app){
        client = new heroku.Heroku({key: "xxxxxx"});
        client.get_app(app, function (error, result) {
            return result;
        });
    }
});

Client side code:

Template.herokuDashboard.helpers({
    appInfo: function() {
        Meteor.call('getHeroku', "meathook-api", function (error, result) {
            console.warn(result);
        } );
    }
});

Heroku takes a while to answer so the answer is undefined.

So what is the best way to catch the async result?

Thank you.

skozz
  • 2,662
  • 3
  • 26
  • 37
  • See [this meteorpedia entry](http://www.meteorpedia.com/read/Category:Fibers_and_Async) on fibers and async. – David Weldon Jul 14 '14 at 18:55
  • Possible duplicate of http://stackoverflow.com/questions/20041177/meteor-code-must-always-run-within-a-fiber-error-when-using-npm-package/20043342#20043342 – imslavko Jul 15 '14 at 20:19

1 Answers1

13

General solution :

Client Side:

    if (Meteor.isClient) {
        Template.herokuDashboard.helpers({
            appInfo: function() {
                return Session.get("herokuDashboard_appInfo");
            }
        });
        Template.herokuDashboard.created = function(){
            Meteor.call('getData', function (error, result) {
                Session.set("herokuDashboard_appInfo",result);
            } );
        }
    }

There is no way to directly return results from Meteor.call. However there are at least 2 solutions (@akshat and @Hubert OG): How to use Meteor methods inside of a template helper

Server Side (Meteor._wrapAsync):

Using Meteor._wrapAsync :

if (Meteor.isServer) {
  var asyncFunc = function(callback){
      setTimeout(function(){
          // callback(error, result);
          // success :
          callback(null,"result");
          // failure:
          // callback(new Error("error"));
      },2000)
  }
  var syncFunc = Meteor._wrapAsync(asyncFunc);
  Meteor.methods({
      'getData': function(){
          var result;
          try{
               result = syncFunc();
          }catch(e){
              console.log("getData method returned error : " + e);
          }finally{
              return result;
          }

      }
  });
}

Proper usage of Future library:

if (Meteor.isServer) {
    Future = Npm.require('fibers/future');

    Meteor.methods({
        'getData': function() {
            var fut = new Future();
            setTimeout(
                Meteor.bindEnvironment(
                    function() {
                        fut.return("test");
                    },
                    function(exception) {
                        console.log("Exception : ", exception);
                        fut.throw(new Error("Async function throw exception"));
                    }
                ),
                1000
            )
            return fut.wait();
        }
    });
}

Using Future library WITHOUT Meteor.bindEnvironment is NOT RECOMMENDED, see:

There is also 3rd approach using Async utilities

Community
  • 1
  • 1
Kuba Wyrobek
  • 5,273
  • 1
  • 24
  • 26
  • Thank you Kuba, but I have already tried that. Maybe I'm doing wrong because it gives me this error: http://cl.ly/image/0A2M2x143k0C Full server side code: http://pastebin.com/RKQH0tzF – skozz Jul 14 '14 at 18:58
  • I changed `fut.ret` to `fut.return`. That should work. – Kuba Wyrobek Jul 14 '14 at 19:02
  • Same error :( `TypeError: Object # has no method 'return'` and `TypeError: Object # has no method 'wait'` I think it's because it is deprecated (https://github.com/meteor/meteor/issues/1311#issuecomment-22686373) but I can't find alternative – skozz Jul 14 '14 at 19:09
  • Do this : `fut["return"](results)` – Kuba Wyrobek Jul 14 '14 at 19:10
  • try: `return fut["wait"]()` – Kuba Wyrobek Jul 14 '14 at 19:18
  • Same :( Trace: http://pastebin.com/n5HZAVFG // Updated final code http://pastebin.com/iQnfMwue – skozz Jul 14 '14 at 19:23
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/57289/discussion-between-kuba-wyrobek-and-skozz). – Kuba Wyrobek Jul 14 '14 at 19:24
  • I think this answer is not accurate, here is a better one: http://stackoverflow.com/questions/20041177/meteor-code-must-always-run-within-a-fiber-error-when-using-npm-package/20043342#20043342 – imslavko Jul 15 '14 at 20:19
  • 1
    @KubaWyrobek ideally you should not use Fibers directly at all. Because there is an additional dynamic environment attached on Fibers and you would not copy it over if you manually create a new fiber. Meteor.bindEnvironment both creates a fiber and attaches the correct environment for you. If you don't do this, you risk to have bugs like not having the request info or login info in a Meteor.call – imslavko Jul 18 '14 at 19:15