I'm trying to use child_process.spawn()
in a Meteor method. I want to capture the PID, stdout, stderr, and exit code from an external process, and store all that in the database.
Everything worked until I added that first insert()
call. With that insert()
, only one 'dummy' document is inserted into the database. I get no error messages in the server console. If I comment out that first insert()
, the other insert()
calls succeed.
// server/app.js
var spawn = Npm.require('child_process').spawn;
Meteor.methods({
start: function() {
var child = spawn('ls', ['/tmp']);
var pid = child.pid;
var wrappedChildStdoutOn = Meteor.wrapAsync(child.stdout.on, child.stdout);
var wrappedChildStderrOn = Meteor.wrapAsync(child.stderr.on, child.stderr);
var wrappedChildOn = Meteor.wrapAsync(child.on, child);
// this insert() breaks upcoming insert() calls!
Stuff.insert({pid: pid, date: new Date(), type: 'dummy', data: 'dummy'});
wrappedChildStdoutOn('data', function (data) {
Stuff.insert({pid: pid, date: new Date(), type: 'stdout', data: data.toString()});
});
wrappedChildStderrOn('data', function (data) {
Stuff.insert({pid: pid, date: new Date(), type: 'stderr', data: data.toString()});
});
wrappedChildOn('exit', function (code) {
Stuff.insert({pid: pid, date: new Date(), type: 'exit', code: code});
});
}
});
What's up with that first insert()
call?
The insert
takes a bit of time, so ls
finishes its output before the insert
completes. By the time you've put the event handler in place, it's too late.
You can fix the issue by moving the first insert
to the end, moving the first insert
before the spawn
call, or adding a no-op function () {}
callback to the insert
so it's called asynchronously.