[Solved] Must use fibers error in promise callback... any ideas?


#1

I’m trying to use a promise based library (HelloSign) to create an iframe form for the client. However, i’m constantly running into issues dealing with fiber scope every time I have to iterate on it.

If I wrap the first then callback with bind environment then the emails send but the other part of the code has a hellosign undefined error. Removing bind env makes this undefined error go away but then the emails throw a ‘must always run in a fiber’.

I’ve tried using a callback with Meteor.call and that doesn’t seem to help any (also wrapping that with bind env doesnt work). If I comment out the Meteor.call everything is fine (though the email doesn’t send obviously).

Any ideas? I’m about to rip out the Meteor method and start up an Apollo endpoint to get rid of this crazyness.

Meteor.methods({
  getIframeURL: function(opts) {
    var options = { ... };

    // create variable scope
    let sigId = null;
    
    const promise = hellosign.signatureRequest.createEmbedded(options)
      .then(function(response){
        sigId = response.signature_request.signature_request_id;
        const signatures = response.signature_request.signatures;
        const primarySignatureId = signatures[0].signature_id;
        
        // send message with signature page to each house member
        signatures.forEach(function(signature, i) {
          hellosign.embedded.getSignUrl(signature.signature_id)
            .then(function(res) {
              // this throws a "must run in fibers error"
              mainServer.call('emailOtherSigners', dataFromRes)
            })
            .catch((err) => { ... });
        });
        
        // continue on with primary applicant signature for iframe url
        return hellosign.embedded.getSignUrl(primarySignatureId);
      })
      .then(function(response){
        // use sigId from outer scope here
        return response.embedded.sign_url; // primary signer url
      })
      .catch(...);
      
      return Promise.resolve(promise).await();
    }
});

#2

Off the top of my head, the library might be using its own promise library under the hood. Sometimes you can tell such libraries which Promise function to use, and feed it Meteor’s. As far as I know, the promises on Meteor server use fibers underneath, due to some abstraction magic. So if this library isn’t using those, then you’d run into environment issues w/ fibers.


#3

Solved… switched to GraphQL to send the data back and forth to skip the fibers issue.


#4

I use MDG validated-methods with callPromise mixin and Future. From the method I return future.wait(), then future.return(response) from the final .then() or future.throw() from .catch().

This way I can call the method like a promise on the client (myMethod.callPromise(args).then(response)), and the response will be the response I get from the future. It’s also possible to call the method synchronously in server using myMethod.call(args).


#5

Also this seems to work in a quick test (after switching lol)… using await works while normal promises do not:

Meteor.methods({
  async testCall() {
    const foo = await Meteor.call("getThing");
    return foo;
  },
  getThing() {
    return "Woot"
  }
})