mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Merge branch 'mongo-runner'
This commit is contained in:
181
app/lib/mongo_runner.js
Normal file
181
app/lib/mongo_runner.js
Normal file
@@ -0,0 +1,181 @@
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
var spawn = require('child_process').spawn;
|
||||
|
||||
var files = require('../lib/files.js');
|
||||
|
||||
var _ = require('../lib/third/underscore.js');
|
||||
|
||||
|
||||
/** Internal.
|
||||
*
|
||||
* If passed, app_dir and port act as filters on the list of running mongos.
|
||||
*
|
||||
* callback is called with (err, [{pid, port, app_dir}])
|
||||
*/
|
||||
var find_mongo_pids = function (app_dir, port, callback) {
|
||||
// 'ps ax' should be standard across all MacOS and Linux.
|
||||
var proc = spawn('ps', ['ax']);
|
||||
var data = '';
|
||||
proc.stdout.on('data', function (d) {
|
||||
data += d;
|
||||
});
|
||||
|
||||
proc.on('exit', function (code, signal) {
|
||||
if (code === 0) {
|
||||
var pids = [];
|
||||
|
||||
_.each(data.split('\n'), function (ps_line) {
|
||||
// matches mongos we start.
|
||||
var m = ps_line.match(/^\s*(\d+).+mongod .+--port (\d+) --dbpath (.+)\/\.meteor\/local\/db\s*$/);
|
||||
if (m && m.length === 4) {
|
||||
var found_pid = parseInt(m[1]);
|
||||
var found_port = parseInt(m[2]);
|
||||
var found_path = m[3];
|
||||
|
||||
if ( (!port || port === found_port) &&
|
||||
(!app_dir || app_dir === found_path)) {
|
||||
pids.push({
|
||||
pid: found_pid, port: found_port, app_dir: found_path});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
callback(null, pids);
|
||||
} else {
|
||||
callback({reason: 'ps exit code ' + code});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// See if mongo is running already. Callback takes a single argument,
|
||||
// 'port', which is the port mongo is running on or null if mongo is not
|
||||
// running.
|
||||
exports.find_mongo_port = function (app_dir, callback) {
|
||||
find_mongo_pids(app_dir, null, function (err, pids) {
|
||||
if (err || pids.length !== 1) {
|
||||
callback(null);
|
||||
return;
|
||||
}
|
||||
|
||||
var pid = pids[0].pid;
|
||||
try {
|
||||
process.kill(pid, 0); // make sure it is still alive
|
||||
} catch (e) {
|
||||
callback(null);
|
||||
return;
|
||||
}
|
||||
|
||||
callback(pids[0].port);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Try to kill any other mongos running on our port. Calls callback
|
||||
// once they are all gone. Callback takes one arg: err (falsy means all
|
||||
// good).
|
||||
//
|
||||
// This is a big hammer for dealing with still running mongos, but
|
||||
// smaller hammers have failed before and it is getting tiresome.
|
||||
var find_mongo_and_kill_it_dead = function (port, callback) {
|
||||
find_mongo_pids(null, port, function (err, pids) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pids.length) {
|
||||
// Send kill attempts and wait. First a SIGINT, then if it isn't
|
||||
// dead within 2 sec, SIGKILL. This goes through the list
|
||||
// serially, but thats OK because there really should only ever be
|
||||
// one.
|
||||
var attempts = 0;
|
||||
var dead_yet = function () {
|
||||
attempts = attempts + 1;
|
||||
var pid = pids[0].pid;
|
||||
var signal = 0;
|
||||
if (attempts === 1)
|
||||
signal = 'SIGINT';
|
||||
else if (attempts === 20 || attempts === 30)
|
||||
signal = 'SIGKILL';
|
||||
try {
|
||||
process.kill(pid, signal);
|
||||
} catch (e) {
|
||||
// it's dead. remove this pid from the list.
|
||||
pids.shift();
|
||||
|
||||
// if no more in the list, we're done!
|
||||
if (!pids.length) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (attempts === 40) {
|
||||
// give up after 4 seconds.
|
||||
callback({
|
||||
reason: "Can't kill running mongo (pid " + pid + ")."});
|
||||
return;
|
||||
}
|
||||
|
||||
// recurse
|
||||
setTimeout(dead_yet, 100);
|
||||
};
|
||||
dead_yet();
|
||||
|
||||
} else {
|
||||
// nothing to kill, fire OK callback
|
||||
callback();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports.launch_mongo = function (app_dir, port, launch_callback, on_exit_callback) {
|
||||
launch_callback = launch_callback || function () {};
|
||||
on_exit_callback = on_exit_callback || function () {};
|
||||
|
||||
// If we are passed an external mongo, assume it is launched and never
|
||||
// exits. Matches code in run.js:exports.run.
|
||||
if (process.env.MONGO_URL) {
|
||||
launch_callback();
|
||||
return;
|
||||
}
|
||||
|
||||
var mongod_path = path.join(files.get_dev_bundle(), 'mongodb/bin/mongod');
|
||||
|
||||
// store data in app_dir
|
||||
var data_path = path.join(app_dir, '.meteor/local/db');
|
||||
files.mkdir_p(data_path, 0755);
|
||||
// add .gitignore if needed.
|
||||
files.add_to_gitignore(path.join(app_dir, '.meteor'), 'local');
|
||||
|
||||
find_mongo_and_kill_it_dead(port, function (err) {
|
||||
if (err) {
|
||||
launch_callback({reason: "Can't kill running mongo: " + err.reason});
|
||||
return;
|
||||
}
|
||||
|
||||
var proc = spawn(mongod_path, [
|
||||
'--bind_ip', '127.0.0.1', '--port', port,
|
||||
'--dbpath', data_path
|
||||
]);
|
||||
|
||||
proc.on('exit', function (code, signal) {
|
||||
on_exit_callback(code, signal);
|
||||
});
|
||||
|
||||
// proc.stderr.setEncoding('utf8');
|
||||
// proc.stderr.on('data', function (data) {
|
||||
// process.stdout.write(data);
|
||||
// });
|
||||
|
||||
proc.stdout.setEncoding('utf8');
|
||||
proc.stdout.on('data', function (data) {
|
||||
// process.stdout.write(data);
|
||||
if (/ \[initandlisten\] waiting for connections on port/.test(data))
|
||||
launch_callback();
|
||||
});
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
@@ -56,25 +56,10 @@ cmd + ": You're not in a Meteor project directory.\n" +
|
||||
process.exit(1);
|
||||
};
|
||||
|
||||
// See if mongo is running already. If so, return the current port. If
|
||||
// not, return null.
|
||||
var find_mongo_port = function (cmd) {
|
||||
var find_mongo_port = function (cmd, callback) {
|
||||
var app_dir = require_project(cmd);
|
||||
|
||||
var fs = require("fs");
|
||||
var pid_path = path.join(app_dir, '.meteor/local/mongod.pid');
|
||||
var port_path = path.join(app_dir, '.meteor/local/mongod.port');
|
||||
var port;
|
||||
|
||||
try {
|
||||
var pid_data = parseInt(fs.readFileSync(pid_path));
|
||||
process.kill(pid_data, 0); // make sure it is still alive
|
||||
port = parseInt(fs.readFileSync(port_path));
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return port;
|
||||
var mongo_runner = require('../lib/mongo_runner.js');
|
||||
mongo_runner.find_mongo_port(app_dir, callback);
|
||||
};
|
||||
|
||||
Commands = [];
|
||||
@@ -401,22 +386,23 @@ Commands.push({
|
||||
|
||||
if (new_argv._.length === 1) {
|
||||
// localhost mode
|
||||
var mongod_port = find_mongo_port("mongo");
|
||||
if (!mongod_port) {
|
||||
process.stdout.write(
|
||||
find_mongo_port("mongo", function (mongod_port) {
|
||||
if (!mongod_port) {
|
||||
process.stdout.write(
|
||||
"mongo: Meteor isn't running.\n" +
|
||||
"\n" +
|
||||
"This command only works while Meteor is running your application\n" +
|
||||
"locally. Start your application first.\n");
|
||||
process.exit(1);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var mongo_url = "mongodb://127.0.0.1:" + mongod_port + "/meteor";
|
||||
var mongo_url = "mongodb://127.0.0.1:" + mongod_port + "/meteor";
|
||||
|
||||
if (new_argv.url)
|
||||
console.log(mongo_url)
|
||||
else
|
||||
deploy.run_mongo_shell(mongo_url);
|
||||
if (new_argv.url)
|
||||
console.log(mongo_url)
|
||||
else
|
||||
deploy.run_mongo_shell(mongo_url);
|
||||
});
|
||||
|
||||
} else if (new_argv._.length === 2) {
|
||||
// remote mode
|
||||
@@ -517,20 +503,21 @@ Commands.push({
|
||||
|
||||
var app_dir = path.resolve(require_project("reset"));
|
||||
|
||||
var mongod_port = find_mongo_port("reset");
|
||||
if (mongod_port) {
|
||||
process.stdout.write(
|
||||
find_mongo_port("reset", function (mongod_port) {
|
||||
if (mongod_port) {
|
||||
process.stdout.write(
|
||||
"reset: Meteor is running.\n" +
|
||||
"\n" +
|
||||
"This command does not work while Meteor is running your application.\n" +
|
||||
"Exit the running meteor development server.\n");
|
||||
process.exit(1);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var local_dir = path.join(app_dir, '.meteor/local');
|
||||
files.rm_recursive(local_dir);
|
||||
var local_dir = path.join(app_dir, '.meteor/local');
|
||||
files.rm_recursive(local_dir);
|
||||
|
||||
process.stdout.write("Project reset.\n");
|
||||
process.stdout.write("Project reset.\n");
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ var httpProxy = require('http-proxy');
|
||||
var files = require('../lib/files.js');
|
||||
var updater = require('../lib/updater.js');
|
||||
var bundler = require('../lib/bundler.js');
|
||||
var mongo_runner = require('../lib/mongo_runner.js');
|
||||
|
||||
var _ = require('../lib/third/underscore.js');
|
||||
|
||||
@@ -125,139 +126,6 @@ var start_proxy = function (outer_port, inner_port, callback) {
|
||||
|
||||
////////// MongoDB //////////
|
||||
|
||||
// Try to kill any other mongos running on our port. Calls callback
|
||||
// once they are all gone. Callback takes one arg: err (falsy means all
|
||||
// good).
|
||||
//
|
||||
// This is a big hammer for dealing with still running mongos, but
|
||||
// smaller hammers have failed before and it is getting tiresome.
|
||||
var find_mongo_and_kill_it_dead = function (data_path, port, callback) {
|
||||
var proc = spawn('ps', ['ax']);
|
||||
var data = '';
|
||||
proc.stdout.on('data', function (d) {
|
||||
data += d;
|
||||
});
|
||||
|
||||
proc.on('exit', function (code, signal) {
|
||||
if (code === 0) {
|
||||
var kill_pids = [];
|
||||
|
||||
_.each(data.split('\n'), function (ps_line) {
|
||||
// matches mongos we start
|
||||
var m = ps_line.match(/^\s*(\d+).+mongod .+--port (\d+) --dbpath (.+\.meteor\/local\/db)\s*$/);
|
||||
if (m && m.length === 4) {
|
||||
var found_pid = m[1];
|
||||
var found_port = m[2];
|
||||
|
||||
if (port === parseInt(found_port)) {
|
||||
kill_pids.push(found_pid);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if (kill_pids.length) {
|
||||
// Send kill attempts and wait. First a SIGINT, then if it isn't
|
||||
// dead within 2 sec, SIGKILL. This goes through the list
|
||||
// serially, but thats OK because there really should only ever be
|
||||
// one.
|
||||
var attempts = 0;
|
||||
var dead_yet = function () {
|
||||
attempts = attempts + 1;
|
||||
var pid = kill_pids[0];
|
||||
var signal = 0;
|
||||
if (attempts === 1)
|
||||
signal = 'SIGINT';
|
||||
else if (attempts === 20 || attempts === 30)
|
||||
signal = 'SIGKILL';
|
||||
try {
|
||||
process.kill(pid, signal);
|
||||
} catch (e) {
|
||||
// it's dead. remove this pid from the list.
|
||||
kill_pids.shift();
|
||||
|
||||
// if no more in the list, we're done!
|
||||
if (!kill_pids.length) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (attempts === 40) {
|
||||
// give up after 4 seconds.
|
||||
callback({
|
||||
reason: "Can't kill running mongo (pid " + pid + ")."});
|
||||
return;
|
||||
}
|
||||
|
||||
// recurse
|
||||
setTimeout(dead_yet, 100);
|
||||
};
|
||||
dead_yet();
|
||||
|
||||
} else {
|
||||
// nothing to kill, fire OK callback
|
||||
callback();
|
||||
}
|
||||
} else {
|
||||
callback({reason: 'ps exit code ' + code});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var launch_mongo = function (app_dir, port, launch_callback, on_exit_callback) {
|
||||
launch_callback = launch_callback || function () {};
|
||||
on_exit_callback = on_exit_callback || function () {};
|
||||
|
||||
// If we are passed an external mongo, assume it is launched and never
|
||||
// exits. Matches code in exports.run.
|
||||
if (process.env.MONGO_URL) {
|
||||
launch_callback();
|
||||
return;
|
||||
}
|
||||
|
||||
var mongod_path = path.join(files.get_dev_bundle(), 'mongodb/bin/mongod');
|
||||
|
||||
// store data in app_dir
|
||||
var data_path = path.join(app_dir, '.meteor/local/db');
|
||||
files.mkdir_p(data_path, 0755);
|
||||
var port_path = path.join(app_dir, '.meteor/local/mongod.port');
|
||||
// add .gitignore if needed.
|
||||
files.add_to_gitignore(path.join(app_dir, '.meteor'), 'local');
|
||||
|
||||
find_mongo_and_kill_it_dead(data_path, port, function (err) {
|
||||
if (err) {
|
||||
console.log("Can't kill running mongo:", err.reason);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var proc = spawn(mongod_path, [
|
||||
'--bind_ip', '127.0.0.1', '--port', port,
|
||||
'--dbpath', data_path
|
||||
]);
|
||||
|
||||
// write port file.
|
||||
fs.writeFileSync(port_path, port.toString(), 'ascii');
|
||||
|
||||
proc.on('exit', function (code, signal) {
|
||||
console.log("Unexpected mongo exit code " + code + ". Restarting.");
|
||||
on_exit_callback();
|
||||
});
|
||||
|
||||
// proc.stderr.setEncoding('utf8');
|
||||
// proc.stderr.on('data', function (data) {
|
||||
// process.stdout.write(data);
|
||||
// });
|
||||
|
||||
proc.stdout.setEncoding('utf8');
|
||||
proc.stdout.on('data', function (data) {
|
||||
// process.stdout.write(data);
|
||||
if (/ \[initandlisten\] waiting for connections on port/.test(data))
|
||||
launch_callback();
|
||||
});
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
var log_to_clients = function (msg) {
|
||||
server_log.push(msg);
|
||||
if (server_log.length > 100) {
|
||||
@@ -678,13 +546,15 @@ exports.run = function (app_dir, bundle_opts, port) {
|
||||
var mongo_err_count = 0;
|
||||
var mongo_err_timer;
|
||||
var launch = function () {
|
||||
launch_mongo(
|
||||
mongo_runner.launch_mongo(
|
||||
app_dir,
|
||||
mongo_port,
|
||||
function () { // On Mongo startup complete
|
||||
restart_server();
|
||||
},
|
||||
function () { // On Mongo dead
|
||||
function (code, signal) { // On Mongo dead
|
||||
console.log("Unexpected mongo exit code " + code + ". Restarting.");
|
||||
|
||||
// if mongo dies 3 times with less than 5 seconds between each,
|
||||
// declare it failed and die.
|
||||
mongo_err_count += 1;
|
||||
|
||||
@@ -65,6 +65,55 @@ $METEOR bundle foo.tar.gz
|
||||
test -f foo.tar.gz
|
||||
|
||||
|
||||
echo "... run"
|
||||
|
||||
# kill any old test meteor
|
||||
# there is probably a better way to do this, but it is at least portable across macos and linux
|
||||
ps ax | grep -e 'meteor.js -p 9100' | grep -v grep | awk '{print $1}' | xargs kill
|
||||
|
||||
! $METEOR mongo > /dev/null 2>&1
|
||||
$METEOR reset > /dev/null 2>&1
|
||||
|
||||
test ! -d .meteor/local
|
||||
! ps ax | grep -e '--bind_ip 127.0.0.1 --port 9102' | grep -v grep > /dev/null
|
||||
|
||||
PORT=9100
|
||||
$METEOR -p $PORT > /dev/null 2>&1 &
|
||||
METEOR_PID=$!
|
||||
|
||||
sleep 1 # XXX XXX lame
|
||||
|
||||
test -d .meteor/local/db
|
||||
ps ax | grep -e '--bind_ip 127.0.0.1 --port 9102' | grep -v grep > /dev/null
|
||||
curl -s "http://localhost:$PORT" > /dev/null
|
||||
|
||||
echo "show collections" | $METEOR mongo
|
||||
|
||||
# kill meteor, see mongo is still running
|
||||
kill $METEOR_PID
|
||||
|
||||
sleep 4 # XXX XXX lame. have to wait for inner app to die via keepalive!
|
||||
|
||||
! ps ax | grep "$METEOR_PID" | grep -v grep > /dev/null
|
||||
ps ax | grep -e '--bind_ip 127.0.0.1 --port 9102' | grep -v grep > /dev/null
|
||||
|
||||
|
||||
echo "... rerun"
|
||||
|
||||
$METEOR -p $PORT > /dev/null 2>&1 &
|
||||
METEOR_PID=$!
|
||||
|
||||
sleep 1 # XXX XXX lame
|
||||
|
||||
ps ax | grep -e '--bind_ip 127.0.0.1 --port 9102' | grep -v grep > /dev/null
|
||||
curl -s "http://localhost:$PORT" > /dev/null
|
||||
|
||||
kill $METEOR_PID
|
||||
ps ax | grep -e '--bind_ip 127.0.0.1 --port 9102' | grep -v grep | awk '{print $1}' | xargs kill
|
||||
|
||||
|
||||
|
||||
|
||||
# XXX more tests here!
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user