From c865318d2bbc51ea29388e189741ee80aa73a191 Mon Sep 17 00:00:00 2001 From: tknew2 Date: Thu, 14 Aug 2014 15:40:30 +0200 Subject: [PATCH] -max-memory-restart option - clean README - fix tests - node_args option added to JSON declaration - desc show node args - fix #487 #490 --- CHANGELOG.md | 5 ++- README.md | 63 +++++++++++++++++++--------------- bin/pm2 | 14 +------- lib/CLI.js | 11 ++++-- lib/CliUx.js | 1 + lib/Common.js | 12 +++++++ lib/God/ActionMethods.js | 30 +++++++++------- lib/God/ClusterMode.js | 6 ++-- lib/God/ForkMode.js | 24 ++++++++++--- lib/ProcessContainer.js | 9 ++--- test/bash/cli.sh | 9 +---- test/bash/cli2.sh | 27 +++------------ test/bash/fork.sh | 2 -- test/bash/gracefulReload.sh | 1 - test/bash/gracefulReload3.sh | 1 - test/bash/harmony.sh | 26 ++++++-------- test/bash/include.sh | 4 +-- test/bash/infinite_loop.sh | 4 --- test/bash/misc.sh | 28 ++++++++++++--- test/fixtures/big-array-es6.js | 23 +++++++++++++ test/fixtures/big-array.js | 8 +++++ test/fixtures/harmony.json | 5 +++ test/fixtures/max-mem.json | 5 +++ 23 files changed, 189 insertions(+), 129 deletions(-) create mode 100644 test/fixtures/big-array-es6.js create mode 100644 test/fixtures/big-array.js create mode 100644 test/fixtures/harmony.json create mode 100644 test/fixtures/max-mem.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d01d5ff..58a8d49b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,9 @@ # 0.10.0 - PM2 Hellfire release -- PM2 Battle testing (https://docs.google.com/spreadsheets/d/1z7hJwI_TBQslkIS07YjgCGlpu8eHy2Wc0Bd5qDNnICE/edit#gid=925366936) +- PM2 is now Battle tested (https://docs.google.com/spreadsheets/d/1z7hJwI_TBQslkIS07YjgCGlpu8eHy2Wc0Bd5qDNnICE/edit#gid=925366936) +- Auto restart memory limit feature via --max-memory-restart (and max_memory_restart via JSON) (https://github.com/Unitech/pm2#max-memory-restart) +- Remove timestamps bu default with pm2 logs - Coffeescript not enabled by default anymore (enhance memory usage) - PM2 Programmatic interface enhanced - Daemon fork system enhanced @@ -15,6 +17,7 @@ - Faster monitoring system - AXM actions unification - Socket errors handled +- PM2_NODE_OPTIONS deprecation (use --node-args instead) # 0.9.6 - 0.9.5 - 0.9.4 diff --git a/README.md b/README.md index 604ab166..8f50769e 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ pm2 is perfect when you need to spread your stateless Node.js code across all CP - Script daemonization - 0s downtime reload for Node apps - Generate SystemV/SystemD startup scripts (Ubuntu, Centos...) +- Set memory limit for process to restart - Pause unstable process (avoid infinite loop) - Restart on file change with `--watch` - Monitoring in console @@ -62,6 +63,7 @@ Thanks in advance and we hope that you like pm2! - [Transitional state of apps](#a4) - [Process listing](#a6) +- [Automatic restart process based on memory](#a6) - [Monitoring CPU/Memory usage](#a7) - [Logs management](#a9) - [Clustering](#a5) @@ -179,6 +181,7 @@ $ pm2 delete all # Will remove all processes from pm2 list # Misc +$ pm2 reset # Reset meta data (restarted time...) $ pm2 updatePM2 # Update in memory pm2 $ pm2 ping # Ensure pm2 daemon has been launched $ pm2 sendSignal SIGUSR2 my-app # Send system signal to script @@ -327,6 +330,25 @@ To get more details about a specific process: $ pm2 describe 0 ``` + +## Automatic restart process based on memory + +Value passed is in megaoctets. Internally it uses the V8 flag `--max-old-space-size=MEM` to make a process exit when memory exceed a certain amount of RAM used. + +CLI: +```bash +$ pm2 start big-array.js --max-memory-restart 20 +``` + +JSON: +```json +{ + "name" : "max_mem", + "script" : "big-array.js", + "max_memory_restart" : "20" +} +``` + ## Monitoring CPU/Memory usage @@ -528,7 +550,6 @@ To watch specifics paths, please use a JSON app declaration, `watch` can take a "watch": ["server", "client"], "ignoreWatch" : ["node_modules", "client/img"] } - ``` @@ -545,6 +566,7 @@ You can define parameters for your apps in `processes.json`: "log_date_format" : "YYYY-MM-DD HH:mm Z", "ignoreWatch" : ["[\\/\\\\]\\./", "node_modules"], "watch" : "true", + "node_args" : "--harmony", "cwd" : "/this/is/a/path/to/start/script", "env": { "NODE_ENV": "production", @@ -613,6 +635,7 @@ Note that if you execute `pm2 start node-app-2` again, it will spawn an addition "cwd" : "/srv/node-app/current", "args" : "['--toto=heya coco', '-d', '1']", "script" : "bin/app.js", + "node_args" : "--harmony", "log_date_format" : "YYYY-MM-DD HH:mm Z", "error_file" : "/var/log/node-app/node-app.stderr.log", "out_file" : "log/node-app.stdout.log", @@ -915,7 +938,6 @@ PM2_BIND_ADDR PM2_API_PORT PM2_GRACEFUL_TIMEOUT PM2_MODIFY_REQUIRE -PM2_NODE_OPTIONS ``` @@ -928,36 +950,21 @@ $ pm2 web ## Enabling Harmony ES6 -### Enable by default for all processes - -You can enable Harmony ES6 by setting `PM2_NODE_OPTIONS='--harmony'` environment variable option when you start pm2 (pm2 should not be already daemonized). - -To pass this option by default, you can edit `~/.pm2/custom_options.sh` and add: - -```bash -export PM2_NODE_OPTIONS='--harmony' -``` - -Then: - -```bash -$ pm2 dump -$ pm2 exit -$ pm2 resurrect -``` - -If ES6 has been enabled you should see this message at the beginning of each pm2 command: - -``` -● ES6 mode -``` - -### Enable for specific processes - +The `--node-args` option permit to launch script with V8 flags, so to enable harmony for a process just do this: ```bash $ pm2 start my_app.js --node-args="--harmony" ``` +And with JSON declaration: + +```bash +[{ + "name" : "ES6", + "script" : "es6.js", + "node_args" : "--harmony" +}] +``` + ## CoffeeScript diff --git a/bin/pm2 b/bin/pm2 index 0a73d21c..8ef23ccc 100755 --- a/bin/pm2 +++ b/bin/pm2 @@ -25,6 +25,7 @@ commander.version(pkg.version) .option('-o --output ', 'specify out log file') .option('-e --error ', 'specify error log file') .option('-p --pid ', 'specify pid file') + .option('--max-memory-restart ', 'specify max memory amount used to autorestart (in megaoctets)') .option('--env ', 'specify environment to get specific env variables (for JSON declaration)') .option('-x --execute-command', 'execute a program using fork system') .option('-u --user ', 'define user when generating startup script') @@ -507,16 +508,3 @@ process.once('satan:client:ready', function() { } }); })(); - -// (function testHarmony() { -// // -// // Harmony test -// // -// try { -// var assert = require('assert') -// , s = new Set(); -// s.add('a'); -// assert.ok(s.has('a')); -// console.log('● ES6 mode'.green); -// } catch(e) {} -// })(); diff --git a/lib/CLI.js b/lib/CLI.js index 6377edd8..bb7b1cf4 100644 --- a/lib/CLI.js +++ b/lib/CLI.js @@ -43,17 +43,22 @@ CLI.start = function(script, opts, cb) { opts = {}; } - if (opts.nodeArgs) + if (opts.nodeArgs) { //maintain backwards compat for space delimited string args if (Array.isArray(opts.nodeArgs)){ - appConf['nodeArgs'] = opts.nodeArgs; + appConf['node_args'] = opts.nodeArgs; } else { - appConf['nodeArgs'] = opts.nodeArgs.split(' '); + appConf['node_args'] = opts.nodeArgs.split(' '); } + } else { + appConf.node_args = []; + } if (opts.scriptArgs) appConf['args'] = JSON.stringify(opts.scriptArgs); if (opts.name) appConf['name'] = opts.name; + if (opts.maxMemoryRestart) + appConf.max_memory_restart = opts.maxMemoryRestart; if (opts.instances) appConf['instances'] = opts.instances; if (opts.error) diff --git a/lib/CliUx.js b/lib/CliUx.js index 417978ef..55c2b43f 100644 --- a/lib/CliUx.js +++ b/lib/CliUx.js @@ -58,6 +58,7 @@ UX.describeTable = function(process) { { 'out log path' : pm2_env.pm_out_log_path }, { 'pid path' : pm2_env.pm_pid_path }, { 'mode' : pm2_env.exec_mode }, + { 'node v8 arguments' : pm2_env.node_args }, { 'watch & reload' : pm2_env.watch ? chalk.green.bold('✔') : '✘' }, { 'interpreter' : pm2_env.exec_interpreter }, { 'restarts' : pm2_env.restart_time }, diff --git a/lib/Common.js b/lib/Common.js index cce86db7..f1dc8da4 100644 --- a/lib/Common.js +++ b/lib/Common.js @@ -63,6 +63,18 @@ Common.resolveAppPaths = function(app, cwd, outputter) { app["pm_exec_path"] = path.resolve(cwd, app.script); delete app.script; + if (app.node_args && !Array.isArray(app.node_args)) + app.node_args = app.node_args.split(' '); + + if (!app.node_args) + app.node_args = []; + + if (app.max_memory_restart && + !isNaN(parseInt(app.max_memory_restart)) && + Array.isArray(app.node_args)) { + app.node_args.push('--max-old-space-size=' + app.max_memory_restart); + } + if (!app["name"]) { app["name"] = p.basename(app["pm_exec_path"]); } diff --git a/lib/God/ActionMethods.js b/lib/God/ActionMethods.js index f0a39ae3..c8aaf148 100644 --- a/lib/God/ActionMethods.js +++ b/lib/God/ActionMethods.js @@ -471,17 +471,17 @@ module.exports = function(God) { * @return */ God.killMe = function(env, cb) { - God.deleteAll({}, function(err, processes) { - console.log('pm2 has been killed by command line'); - God.bus.emit('pm2:kill', { - status : 'killed', - msg : 'pm2 has been killed via CLI' - }); - setTimeout(function() { - cb(null, {msg : 'pm2 killed'}); - process.exit(cst.SUCCESS_EXIT); - }, 800); + console.log('PM2 has been killed by user command'); + God.bus.emit('pm2:kill', { + status : 'killed', + msg : 'pm2 has been killed via CLI' }); + setTimeout(function() { + cb(null, {msg : 'pm2 killed'}); + }, 200); + setTimeout(function() { + process.exit(cst.SUCCESS_EXIT); + }, 300); }; @@ -559,10 +559,16 @@ module.exports = function(God) { processIds.forEach(function (id) { var cluster = God.clusters_db[id]; + if (cluster.pm2_env.exec_mode == 'cluster_mode') cluster.send({type:'log:reload'}); - else - cluster._reloadLogs(function() { + else // Fork mode + cluster._reloadLogs(function(err) { + if (err) { + God.logAndGenerateError(err); + return cb(new Error(err)); + }; + return false; }); console.log('Reloading logs for process id %d', id); }); diff --git a/lib/God/ClusterMode.js b/lib/God/ClusterMode.js index e11b3228..052b47af 100644 --- a/lib/God/ClusterMode.js +++ b/lib/God/ClusterMode.js @@ -36,8 +36,8 @@ module.exports = function ClusterMode(God) { console.log('Entering in node wrap logic (cluster_mode) for script %s', env_copy.pm_exec_path); - if (env_copy.nodeArgs && Array.isArray(env_copy.nodeArgs)) { - cluster.settings.execArgv = env_copy.nodeArgs; + if (env_copy.node_args && Array.isArray(env_copy.node_args)) { + cluster.settings.execArgv = env_copy.node_args; } try { @@ -71,7 +71,7 @@ module.exports = function ClusterMode(God) { } }); - + //delete clu.process._handle.owner; return cb(null, clu); diff --git a/lib/God/ForkMode.js b/lib/God/ForkMode.js index af959d25..59f41b18 100644 --- a/lib/God/ForkMode.js +++ b/lib/God/ForkMode.js @@ -40,8 +40,8 @@ module.exports = function ForkMode(God) { if (interpreter !== 'none') { command = interpreter; - if (pm2_env.nodeArgs && Array.isArray(pm2_env.nodeArgs)) { - args = args.concat(pm2_env.nodeArgs); + if (pm2_env.node_args && Array.isArray(pm2_env.node_args)) { + args = args.concat(pm2_env.node_args); } if (process.env.PM2_NODE_OPTIONS) { @@ -86,15 +86,31 @@ module.exports = function ForkMode(God) { function startLogging(cb) { stdout = fs.createWriteStream(outFile, { flags : 'a' }); + stdout.on('error', function(e) { + God.logAndGenerateError(e); + return cb(e); + }); + stdout.on('open', function() { stderr = fs.createWriteStream(errFile, { flags : 'a' }); + + stderr.on('error', function(e) { + God.logAndGenerateError(e); + return cb(e); + }); + stderr.on('open', function() { - return cb(); + return cb(null); }); }); } - startLogging(function() { + startLogging(function(err) { + if (err) { + God.logAndGenerateError(err); + return cb(err); + }; + getugid(function(e, uid, gid){ if(e){ God.logAndGenerateError(e); diff --git a/lib/ProcessContainer.js b/lib/ProcessContainer.js index 0cf0ea18..0f337dbc 100644 --- a/lib/ProcessContainer.js +++ b/lib/ProcessContainer.js @@ -2,6 +2,10 @@ // Child wrapper. Redirect output to files, assign pid & co. // by Strzelewicz Alexandre +// Rename process +if (process.env.name != null) + process.title = 'pm2: ' + process.env.name; + var fs = require('fs'); var p = require('path'); var cst = require('../constants'); @@ -30,9 +34,6 @@ var cst = require('../constants'); if (process.env.args != null) process.argv = process.argv.concat(eval(process.env.args)); - // Rename process - if (process.env.name != null) - process.title = 'pm2: ' + process.env.name; exec(script, outFile, errFile); @@ -79,7 +80,7 @@ function exec(script, outFile, errFile) { process.chdir(process.env.PWD || p.dirname(script)); var stderr, stdout; - + if(p.extname(script) == '.coffee') { require('coffee-script/register'); } diff --git a/test/bash/cli.sh b/test/bash/cli.sh index 71966f3c..0c780cfd 100755 --- a/test/bash/cli.sh +++ b/test/bash/cli.sh @@ -7,9 +7,6 @@ echo -e "\033[1mRunning tests:\033[0m" cd $file_path -$pm2 kill -spec "kill daemon" - # # Different way to stop process # @@ -137,11 +134,7 @@ spec "Should get the right JSON with HttpInterface file launched" # Restart only one process # $pm2 restart 1 -sleep 0.3 -$http_get -q http://localhost:9615/ -O $JSON_FILE -OUT=`cat $JSON_FILE | grep -o "restart_time\":1" | wc -l` -[ $OUT -eq 1 ] || fail "$1" -success "$1" +should 'should has restarted process' 'restart_time: 1' 1 # # Restart all processes diff --git a/test/bash/cli2.sh b/test/bash/cli2.sh index 538ed9e3..76d46f14 100755 --- a/test/bash/cli2.sh +++ b/test/bash/cli2.sh @@ -21,7 +21,7 @@ $pm2 restart echo.js spec "Should restart an app by script.js (TRANSITIONAL STATE)" ############### -$pm2 kill +$pm2 delete all echo "---- BY_NAME Start an app, stop it, if state stopped and started, restart stopped app" @@ -33,30 +33,13 @@ $pm2 restart gege should 'should app be online once restart called' 'online' 1 ############### -$pm2 kill +$pm2 delete all echo "Start an app, start it one more time, if started, throw message" $pm2 start echo.js $pm2 start echo.js ispec "Should not re start app" - -############### -$pm2 kill - -cd ../.. - -echo "Change path try to exec" -$pm2 start test/fixtures/echo.js -should 'should app be online' 'online' 1 -$pm2 stop test/fixtures/echo.js -should 'should app be stopped' 'stopped' 1 -$pm2 start test/fixtures/echo.js -should 'should app be online' 'online' 1 - -cd - - - ########### DELETED STUFF BY ID $pm2 kill @@ -65,14 +48,14 @@ $pm2 delete 0 should 'should has been deleted process by id' "name: 'echo'" 0 ########### DELETED STUFF BY NAME -$pm2 kill +$pm2 delete all $pm2 start echo.js --name test $pm2 delete test should 'should has been deleted process by name' "name: 'test'" 0 ########### DELETED STUFF BY SCRIPT -$pm2 kill +$pm2 delete all $pm2 start echo.js $pm2 delete echo.js @@ -81,7 +64,7 @@ should 'should has been deleted process by script' "name: 'echo'" 0 ########### OPTIONS OUTPUT FILES -$pm2 kill +$pm2 delete all $pm2 start echo.js -o outech.log -e errech.log --name gmail -i 10 sleep 0.5 diff --git a/test/bash/fork.sh b/test/bash/fork.sh index c7d2fd3c..d1c7d20f 100644 --- a/test/bash/fork.sh +++ b/test/bash/fork.sh @@ -6,8 +6,6 @@ source "${SRC}/include.sh" cd $file_path ########### Fork mode -$pm2 kill - $pm2 start echo.js -x should 'should has forked app' 'fork_mode' 1 diff --git a/test/bash/gracefulReload.sh b/test/bash/gracefulReload.sh index 17258d05..16de9963 100644 --- a/test/bash/gracefulReload.sh +++ b/test/bash/gracefulReload.sh @@ -8,7 +8,6 @@ cd $file_path echo "################## GRACEFUL RELOAD ###################" ############### -$pm2 kill echo "Launching" $pm2 start graceful-exit.js -i 4 --name="graceful" -o "grace.log" -e "grace-err.log" diff --git a/test/bash/gracefulReload3.sh b/test/bash/gracefulReload3.sh index e50cca77..87b93972 100644 --- a/test/bash/gracefulReload3.sh +++ b/test/bash/gracefulReload3.sh @@ -8,7 +8,6 @@ cd $file_path echo "################## GRACEFUL RELOAD 3 ###################" ############### -$pm2 kill echo "Launching" $pm2 start graceful-exit-send.js -i 2 --name="graceful3" -o "grace3.log" -e "grace-err3.log" diff --git a/test/bash/harmony.sh b/test/bash/harmony.sh index dd9433b2..fe037293 100644 --- a/test/bash/harmony.sh +++ b/test/bash/harmony.sh @@ -11,33 +11,29 @@ echo "################ HARMONY ES6" $pm2 start harmony.js sleep 2 $pm2 list -ishould 'should not fail when passing harmony option to V8' 'restart_time: 0' 1 +should 'should FAIL when not passing harmony option to V8' 'restart_time: 0' 0 $pm2 list -$pm2 kill - -PM2_NODE_OPTIONS='--harmony' `pwd`/../../bin/pm2 start harmony.js -sleep 2 -$pm2 list -should 'should not fail when passing harmony option to V8' 'restart_time: 0' 1 -$pm2 kill +$pm2 delete all $pm2 start harmony.js --node-args="--harmony" sleep 2 $pm2 list -should 'should not fail when passing node-args=harmony opts' 'restart_time: 0' 1 -$pm2 kill +should 'should not fail when passing node-args=harmony opts in CLUSTERMODE' 'restart_time: 0' 1 +$pm2 delete all echo "################ HARMONY / NODEARGS ES6 FORK MODE" $pm2 start harmony.js --node-args="--harmony" -x sleep 2 $pm2 list -should 'should not fail when passing node-args=harmony opts' 'restart_time: 0' 1 -$pm2 kill +should 'should not fail when passing node-args=harmony opts in FORKMODE' 'restart_time: 0' 1 +$pm2 delete all +echo "################## NODE ARGS VIA JSON" -PM2_NODE_OPTIONS='--harmony' $pm2 start harmony.js -x +$pm2 start harmony.json sleep 2 $pm2 list -should 'should not fail when passing node-args=harmony opts' 'restart_time: 0' 1 -$pm2 kill +should 'should not fail when passing harmony option to V8 via node_args in JSON files' 'restart_time: 0' 1 + +$pm2 delete all diff --git a/test/bash/include.sh b/test/bash/include.sh index 8ac71c25..2d522b30 100644 --- a/test/bash/include.sh +++ b/test/bash/include.sh @@ -22,7 +22,7 @@ file_path="test/fixtures" $pm2 kill # Determine wget / curl -which wget +which wget > /dev/null if [ $? -eq 0 ] then http_get="wget" @@ -31,8 +31,6 @@ else exit 1; fi -echo $http_get - function fail { echo -e "######## \033[31m ✘ $1\033[0m" exit 1 diff --git a/test/bash/infinite_loop.sh b/test/bash/infinite_loop.sh index 16d86b8f..36e0a52b 100644 --- a/test/bash/infinite_loop.sh +++ b/test/bash/infinite_loop.sh @@ -8,10 +8,6 @@ cd $file_path echo "Starting infinite loop tests" -$pm2 kill - - - $pm2 start killtoofast.js --name unstable-process echo -n "Waiting for process to restart too many times and pm2 to stop it" diff --git a/test/bash/misc.sh b/test/bash/misc.sh index 72e4eb72..cc2b424c 100644 --- a/test/bash/misc.sh +++ b/test/bash/misc.sh @@ -7,8 +7,27 @@ cd $file_path echo -e "\033[1mRunning tests:\033[0m" +# +# Max memory auto restart option +# +# -max-memory-restart option && maxMemoryRestart (via JSON file) +# +$pm2 start big-array.js --max-memory-restart 19 +sleep 7 +$pm2 list +should 'process should been restarted' 'restart_time: 0' 0 -$pm2 kill +$pm2 delete all + +# +# Via JSON +# +$pm2 start max-mem.json +sleep 7 +$pm2 list +should 'process should been restarted' 'restart_time: 0' 0 + +$pm2 delete all $pm2 start env.js @@ -27,7 +46,7 @@ else fail "environment defined ? wtf ?" fi -$pm2 kill +$pm2 delete all $pm2 start env.json @@ -37,7 +56,7 @@ sleep 1 OUT=`cat $OUT_LOG | head -n 1` -if [ $OUT = "undefined" ] +if [ "$OUT" = "undefined" ] then fail "environment variable hasnt been defined" else @@ -79,10 +98,9 @@ ispec 'file outmerge-0.log should not exist' rm outmerge* ########### coffee cluster test -$pm2 kill +$pm2 delete all $pm2 start echo.coffee should 'process should not have been restarted' 'restart_time: 0' 1 should 'process should be online' "status: 'online'" 1 - diff --git a/test/fixtures/big-array-es6.js b/test/fixtures/big-array-es6.js new file mode 100644 index 00000000..b08ce2b0 --- /dev/null +++ b/test/fixtures/big-array-es6.js @@ -0,0 +1,23 @@ + + +var obj = {}; +var i = 0; + +setInterval(function() { + obj[i] = Array.apply(null, new Array(99999)).map(String.prototype.valueOf,"hi"); + i++; +}, 2); + + +(function testHarmony() { + // + // Harmony test + // + try { + var assert = require('assert') + , s = new Set(); + s.add('a'); + assert.ok(s.has('a')); + console.log('● ES6 mode'.green); + } catch(e) {} +})(); diff --git a/test/fixtures/big-array.js b/test/fixtures/big-array.js new file mode 100644 index 00000000..d4236fbe --- /dev/null +++ b/test/fixtures/big-array.js @@ -0,0 +1,8 @@ + +var obj = {}; +var i = 0; + +setInterval(function() { + obj[i] = Array.apply(null, new Array(99999)).map(String.prototype.valueOf,"hi"); + i++; +}, 2); diff --git a/test/fixtures/harmony.json b/test/fixtures/harmony.json new file mode 100644 index 00000000..99ed3067 --- /dev/null +++ b/test/fixtures/harmony.json @@ -0,0 +1,5 @@ +{ + "name" : "ES6", + "script" : "harmony.js", + "node_args" : "--harmony" +} diff --git a/test/fixtures/max-mem.json b/test/fixtures/max-mem.json new file mode 100644 index 00000000..1d44d15b --- /dev/null +++ b/test/fixtures/max-mem.json @@ -0,0 +1,5 @@ +{ + "name" : "max_mem", + "script" : "big-array.js", + "max_memory_restart" : "19" +}