Meteor code must always run within a Fiber. (using Dockerode)

Hi,
I’m really lost with this error. I’ve read so many things on internet about it but I can’t find the real solution… I’m trying to write in the console the id of my 2 running Docker container with Meteor.

There is my code

   'infosContainers.listInfosContainers': function() {
      docker.listContainers(function (err, containers) {
        containers.forEach(function (containerInfo) {
          console.log("in the forEach");
          InfosContainers.insert({
            idContainer: containerInfo.Id
          });
          console.log("container: " + containerInfo.Id);
        });
          console.log("end of docker.listContainers");
      });
    console.log("end of infosContainers.listContainers");
},

Someone could help me to remove the error ?

So the solution is:

'infosContainers.listInfosContainers': function() {

     docker.listContainers(Meteor.bindEnvironment(function (err, containers) {
       containers.forEach(Meteor.bindEnvironment(function (containerInfo) {
         console.log("in the forEach");
         InfosContainers.insert({
           idContainer: containerInfo.Id
         });
         console.log("container: " + containerInfo.Id);
       }));
         console.log("end of docker.listContainers");
     }));

   console.log("end of infosContainers.listContainers");
},

The problem arises because you are using an async function that uses a callback. Nothing is, or should, be wrong with that. But since you are using meteor methods inside (the insert), and the callback is executed outside of the meteor scope you need to either bind meteor to it or wrap the async function to use as a sync function meteor way.

Either bind the meteor environment:

'infosContainers.listInfosContainers': function() {
      docker.listContainers(Meteor.bindEnvironment(function (err, containers) {
        containers.forEach(function (containerInfo) {
          console.log("in the forEach");
          InfosContainers.insert({
            idContainer: containerInfo.Id
          });
          console.log("container: " + containerInfo.Id);
        });
          console.log("end of docker.listContainers");
      }));
    console.log("end of infosContainers.listContainers");
},

Or better, use wrapAsync:

var docker_listContainers = Meteor.wrapAsync(docker.listContainers,docker);
//wrapAsync second parameter is the optional 'this' against which to call the method.
'infosContainers.listInfosContainers': function() {
    var containers = docker_listContainers();
    containers.forEach(function (containerInfo) {
      console.log("in the forEach");
      InfosContainers.insert({
        idContainer: containerInfo.Id
      });
      console.log("container: " + containerInfo.Id);
    });    
    console.log("end of infosContainers.listContainers");
},

Both options are good, but the last one (using wrapAsync) makes it easier for the developper as it let’s them use any asynchronous function exactly like synchronous ones, just like most Meteor functions work. Note that I created a variable to store the wrapped function, it is not mandatory but preferable if it is a function that is going to be reused a couple times, just like you could do it with the binded function in option 1.

Read more on wrapAsync: https://docs.meteor.com/api/core.html#Meteor-wrapAsync
or on both methods: https://www.eventedmind.com/items/meteor-what-is-meteor-bindenvironment

1 Like

You might not need to bind the forEach. Unless it is also an asynchronous function provided by your docker library.

Thank you for the help and all the informations !

1 Like

your welcome. Don’t hesitate to ask if you need more info.