vsivsi / meteor-job-collection

A persistent and reactive job queue for Meteor, supporting distributed workers that can run anywhere.
https://atmospherejs.com/vsivsi/job-collection
Other
388 stars 68 forks source link

Meteor code must always run within a Fiber... #229

Open mklueh opened 7 years ago

mklueh commented 7 years ago

Hello, I´m struggeling for days now to get the async stuff working with Meteor.

My usecase:

I want to spin up multiple processes, where each one has to do a certain number of exec calls to other programs, file operations and if possible MongoDB queries. Those processes should run within my meteor application. I don´t want to have extra servers for that.

I´ve tried using "child_process", but as Meteor builds the app and wraps files together, I cannot reference my worker file like in plain node.

meteor-job-collection looks like the best choice so far, but I cannot get the simplest implementation working.

Here is the code of my initializing script


import MyJob from '/server/services/myJob';

let jobs= JobCollection('app.jobs');

if (Meteor.isServer) {
    Meteor.startup(function () {
        return jobs.startJobServer();
    });

    let job = new MyJob(jobs, 'sendEmail',
        {
            address: 'bozo@clowns.com',
            subject: 'Critical rainbow hair shortage',
            message: 'LOL; JK, KThxBye.'
         }
      );
     job.priority('normal').retry({retries: 10}).save();
}

And here my worker script

const exec = require('exec');
const DDP = require('ddp');
const DDPlogin = require('ddp-login');
const Job = require('meteor-job');

if (Meteor.isServer) {
    let ddp = new DDP({
        host: "localhost",
        port: 3000,
        method: 'account',
        retry: 5,
        account: null,
        pass: null,
        use_ejson: true
    });
    Job.setDDP(ddp);
    ddp.connect(function (err) {

        console.log("connected");
        if (err) throw err;

        DDPlogin(ddp, function () {
            console.log("login");

            let workers = Job.processJobs('app.jobs', 'sendEmail',
                function (job, cb) {
                    console.log(job);
                }
            );
        })

    });
}

First of all, the DDPLogin callback does basically nothing. It doesn´t get fired at all, so I´ve decided to remove it for now.

Then I get this error:

packages\meteor.js:1075
W20170415-19:16:25.187(2)? (STDERR)     throw new Error("Meteor code must always run within a Fiber. " +
W20170415-19:16:25.187(2)? (STDERR)     ^
W20170415-19:16:25.188(2)? (STDERR) 
W20170415-19:16:25.188(2)? (STDERR) Error: Meteor code must always run within a Fiber. Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment.
W20170415-19:16:25.188(2)? (STDERR)     at Object.Meteor._nodeCodeMustBeInFiber (packages\meteor.js:1075:11)
W20170415-19:16:25.189(2)? (STDERR)     at [object Object]._.extend.get (packages\meteor.js:1087:12)
W20170415-19:16:25.189(2)? (STDERR)     at withoutInvocation (packages\meteor.js:443:28)
W20170415-19:16:25.189(2)? (STDERR)     at bindAndCatch (packages\meteor.js:452:33)
W20170415-19:16:25.190(2)? (STDERR)     at Object._.extend.setTimeout (packages\meteor.js:468:23)
W20170415-19:16:25.190(2)? (STDERR)     at _setImmediate (C:\Users\MyPC\Documents\Workspaces\Application\node_modules\meteor-job\lib\job_class.js:118:32)
W20170415-19:16:25.191(2)? (STDERR)     at JobQueue.resume (C:\Users\MyPC\Documents\Workspaces\Application\node_modules\meteor-job\lib\job_class.js:390:7)
W20170415-19:16:25.191(2)? (STDERR)     at new JobQueue (C:\Users\MyPC\Documents\Workspaces\Application\node_modules\meteor-job\lib\job_class.js:191:12)
W20170415-19:16:25.191(2)? (STDERR)     at C:\Users\MyPC\Documents\Workspaces\Application\node_modules\meteor-job\lib\job_class.js:154:47
W20170415-19:16:25.192(2)? (STDERR)     at Function.JobQueue [as processJobs] (C:\Users\MyPC\Documents\Workspaces\Application\node_modules\meteor-job\lib\job_class.js:156:11)
=> Exited with code: 1

I haven´t seen anything with fibers in your examples or in the documentation, so I think it should work without them at all until I call some external APIs or whatever.

Another weird thing is I´m getting the collection "app.jobs.jobs" instead of what I´ve specified "app.jobs" - not important, but weird.

What is wrong with my implementation and why do I get the fiber error with the example code?

vsivsi commented 7 years ago

The main problem I see above is that in the Meteor server environment, most of that code above is not necessary and probably won't even work. e.g. You don't need the npm DDP library, or the DDPLogin or anything, because on a Meteor server you are already running in the Meteor environment and implicitly connected and authenticated by virtue of being in Meteor server code.

The example code you grabbed is for use in a pure node.js environment (no Meteor APIs, no Fibers, etc), not within Meteor the way you are trying to use it.

One other thing is if your workers will be calling non-Fiber aware async code (using callbacks or promises) then you will need to become acquainted with Meteor.bindEnvironment() and relatives. Google it, there are a lot of resources out there that explain this stuff.

Hope that helps