diff --git a/src/cli/cli-definitions.js b/src/cli/cli-definitions.js index b8acc3de..abfade27 100644 --- a/src/cli/cli-definitions.js +++ b/src/cli/cli-definitions.js @@ -221,5 +221,9 @@ export default { env: "PARSE_SERVER_SCHEMA_CACHE_TTL", help: "The TTL for caching the schema for optimizing read/write operations. You should put a long TTL when your DB is in production. default to 0; disabled.", action: numberParser("schemaCacheTTL"), + }, + "cluster": { + help: "Run with cluster, optionally set the number of processes default to os.cpus().length", + action: numberParser("cluster"), } }; diff --git a/src/cli/parse-server.js b/src/cli/parse-server.js index de84a50c..a09445f4 100755 --- a/src/cli/parse-server.js +++ b/src/cli/parse-server.js @@ -4,6 +4,8 @@ import { ParseServer } from '../index'; import definitions from './cli-definitions'; import program from './utils/commander'; import { mergeWithOptions } from './utils/commander'; +import cluster from 'cluster'; +import os from 'os'; program.loadDefinitions(definitions); @@ -48,12 +50,7 @@ if (!options.appId || !options.masterKey || !options.serverURL) { process.exit(1); } -const app = express(); -const api = new ParseServer(options); -app.use(options.mountPath, api); - -var server = app.listen(options.port, function() { - +function logStartupOptions(options) { for (let key in options) { let value = options[key]; if (key == "masterKey") { @@ -61,15 +58,46 @@ var server = app.listen(options.port, function() { } console.log(`${key}: ${value}`); } - console.log(''); - console.log('parse-server running on '+options.serverURL); -}); +} -var handleShutdown = function() { - console.log('Termination signal received. Shutting down.'); - server.close(function () { - process.exit(0); +function startServer(options, callback) { + const app = express(); + const api = new ParseServer(options); + app.use(options.mountPath, api); + + var server = app.listen(options.port, callback); + + var handleShutdown = function() { + console.log('Termination signal received. Shutting down.'); + server.close(function () { + process.exit(0); + }); + }; + process.on('SIGTERM', handleShutdown); + process.on('SIGINT', handleShutdown); +} + +if (options.cluster) { + const numCPUs = typeof options.cluster === 'number' ? options.cluster : os.cpus().length; + if (cluster.isMaster) { + logStartupOptions(options); + for(var i = 0; i < numCPUs; i++) { + cluster.fork(); + } + cluster.on('exit', (worker, code, signal) => { + console.log(`worker ${worker.process.pid} died... Restarting`); + cluster.fork(); + }); + } else { + startServer(options, () => { + console.log('['+process.pid+'] parse-server running on '+options.serverURL); + }); + } +} else { + startServer(options, () => { + logStartupOptions(options); + console.log(''); + console.log('['+process.pid+'] parse-server running on '+options.serverURL); }); -}; -process.on('SIGTERM', handleShutdown); -process.on('SIGINT', handleShutdown); +} +