├── .circleci └── config.yml ├── .eslintrc.js ├── .gitignore ├── .prettierrc ├── CHANGELOG.md ├── LICENSE ├── README.md ├── bin ├── forever └── monitor ├── lib ├── forever.js ├── forever │ ├── cli.js │ └── worker.js └── util │ ├── config-utils.js │ └── utils.js ├── package.json └── test ├── cli-test ├── core ├── daemonic-inheritance-test.js ├── start-stop-json-array-test.js ├── start-stop-json-obj-test.js ├── start-stop-relative-test.js ├── stopall-peaceful-test.js ├── stopbypid-peaceful-test.js ├── tail-stopall-test.js └── uptime-test.js ├── fixtures ├── cluster-fork-mode.js ├── log-on-interval.js ├── server.js ├── server.json ├── servers.json └── start-daemon.js ├── helpers ├── index.js ├── macros.js ├── mocks │ ├── child-process.js │ ├── monitor.js │ └── stream.js └── utils.js ├── mocha ├── cli │ ├── cli.spec.js │ └── scripts │ │ └── dir with spaces │ │ └── script_name.js └── util │ └── config-utils.spec.js └── worker ├── multiple-workers-test.js └── simple-test.js /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | commands: 4 | test-nodejs: 5 | steps: 6 | - run: 7 | name: Versions 8 | command: npm version 9 | - checkout 10 | - restore_cache: 11 | keys: 12 | - v{{ .Environment.CIRCLE_CACHE_VERSION }}-{{ arch }}-npm-cache-{{ .Branch }}-{{ .Environment.CIRCLE_JOB }} 13 | - v{{ .Environment.CIRCLE_CACHE_VERSION }}-{{ arch }}-npm-cache-master-{{ .Environment.CIRCLE_JOB }} 14 | - run: 15 | name: Install dependencies 16 | command: npm install 17 | - run: 18 | name: Test 19 | command: npm run test:ci 20 | - save-npm-cache 21 | save-npm-cache: 22 | steps: 23 | - save_cache: 24 | key: v{{ .Environment.CIRCLE_CACHE_VERSION }}-{{ arch }}-npm-cache-{{ .Branch }}-{{ .Environment.CIRCLE_JOB }}-{{ checksum "package-lock.json" }} 25 | paths: 26 | - ~/.npm/_cacache 27 | jobs: 28 | node-v6: 29 | docker: 30 | - image: node:6 31 | steps: 32 | - test-nodejs 33 | node-v8: 34 | docker: 35 | - image: node:8 36 | steps: 37 | - test-nodejs 38 | node-v10: 39 | docker: 40 | - image: node:10 41 | steps: 42 | - test-nodejs 43 | node-v12: 44 | docker: 45 | - image: node:12 46 | steps: 47 | - test-nodejs 48 | node-v14: 49 | docker: 50 | - image: node:14 51 | steps: 52 | - test-nodejs 53 | node-v16: 54 | docker: 55 | - image: node:16 56 | steps: 57 | - test-nodejs 58 | 59 | workflows: 60 | version: 2 61 | node-multi-build: 62 | jobs: 63 | - node-v6 64 | - node-v8 65 | - node-v10 66 | - node-v12 67 | - node-v14 68 | - node-v16 69 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parserOptions: { 3 | ecmaVersion: 2015, 4 | }, 5 | extends: [ 6 | 'eslint:recommended', 7 | 'prettier', 8 | ], 9 | plugins: [], 10 | rules: { 11 | 'no-console': 0, 12 | 'no-octal': 0, 13 | 'no-var': 2, 14 | 'no-empty': 0, 15 | 'no-debugger': 2, 16 | 'prefer-const': 2, 17 | 'no-fallthrough': 2, 18 | 'require-atomic-updates': 0, 19 | 'no-useless-escape': 0, 20 | 'no-unused-vars': 0, 21 | "no-var": 0 // ToDo 22 | }, 23 | env: { 24 | node: true, 25 | mocha: true, 26 | es6: true, 27 | }, 28 | }; 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | test/*.log 3 | node_modules/ 4 | node_modules/* 5 | npm-debug.log 6 | .*.sw[op] 7 | test/fixtures/*.log 8 | .idea 9 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "es5", 4 | "arrowParens": "always", 5 | "endOfLine": "lf" 6 | } 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 4.0.3 / Fri, 28 January 2022 2 | ========================= 3 | 4 | - [fix] Upgrade Winston [#1128] 5 | 6 | 4.0.2 / Mon, 10 January 2022 7 | ========================= 8 | 9 | - [fix] Pin colors.js version [#1127] 10 | 11 | 4.0.1 / Sat, 12 June 2021 12 | ========================= 13 | 14 | - [fix] Configstore init and usage fixes [#1115] 15 | 16 | 4.0.0 / Tue, 06 May 2021 17 | ========================= 18 | 19 | - [security] Replace nconf with configstore [#1112] 20 | - [security] Replace yargs with getopts [#1110] 21 | 22 | 3.0.4 / Sat, 21 Nov 2020 23 | ========================= 24 | 25 | - [security] Update forever-monitor and remove utile to get rid of vulnerabilities 26 | 27 | 3.0.3 / Sat, 21 Nov 2020 28 | ========================= 29 | 30 | - [security] Update forever-monitor and remove broadway to get rid of vulnerable minimist version [#1098] 31 | 32 | 3.0.2 / Sat, 21 Nov 2020 33 | ========================= 34 | 35 | - [doc] Add project deprecation warning 36 | 37 | 3.0.1 / Sun, 22 Aug 2020 38 | ========================= 39 | 40 | - [security] Replaced optimist with yargs [#1093] 41 | 42 | 3.0.0 / Fri, 22 May 2020 43 | ========================= 44 | 45 | - [security] Update forever-monitor [#1081] 46 | 47 | 2.0.0 / Sun, 05 Jan 2020 48 | ========================= 49 | 50 | - [security] Update dependencies [#1050][#1051][#1052] 51 | - [major] Drop support for Node.js versions < 6 [#1049] 52 | - [doc] add '--version' to help text [#1041] 53 | 54 | 1.0.1 / Sun, 05 Jan 2020 55 | ========================= 56 | 57 | - [security] Update forever-monitor [#1047] 58 | - [doc] Add information about the fact that no output is appended to the logs after forever stop/stopall is called [#1015] 59 | - [doc] Add list of supported columns [#1029] 60 | 61 | 1.0.0 / Wed, 03 Apr 2019 62 | ========================= 63 | 64 | - [major] 1.0.0 due to breaking change introduced in [#1017]. 65 | - [security] Update utile to get rid of security warning [#1022] 66 | - [security] Remove dependency on timespan [#1014] 67 | - [fix] Fix support for Node 10+ [#979] 68 | - [change] Propagate error when failing to create directories on startup [#1017] 69 | - [doc] Add example for referencing -l -o and -e parameters from within a JSON config file [#869] 70 | 71 | 0.14.2 / Tue, 30 Jun 2015 72 | ========================= 73 | * [804b5b1](https://github.com/foreverjs/forever/commit/804b5b1) [dist] Version bump. 0.14.2 (`indexzero`) 74 | * [1e4953d](https://github.com/foreverjs/forever/commit/1e4953d) [fix] Do not break tests. (`indexzero`) 75 | * [310edd2](https://github.com/foreverjs/forever/commit/310edd2) fixes #699 (`Mike van Rossum`) 76 | * [19f7909](https://github.com/foreverjs/forever/commit/19f7909) Add license attribute (`Gilad Peleg`) 77 | * [36fbaf1](https://github.com/foreverjs/forever/commit/36fbaf1) isNaN() doesn't check if the value is numeric; it only checks if it is equal to NaN. In particular it won't catch null. (`Craig R. Hughes`) 78 | * [31c2f16](https://github.com/foreverjs/forever/commit/31c2f16) Remove overwhelm, highlight forever start in doc (`Doug Carroll`) 79 | * [19a0de8](https://github.com/foreverjs/forever/commit/19a0de8) Update CHANGELOG.md. (`XhmikosR`) 80 | 81 | v0.14.1 / Wed, 4 Feb 2015 82 | ========================= 83 | * [509eaf2](https://github.com/foreverjs/forever/commit/509eaf2) [dist] Version bump. 0.14.1 (`indexzero`) 84 | * [e5296a2](https://github.com/foreverjs/forever/commit/e5296a2) [minor] Small style change. (`indexzero`) 85 | * [c33f56e](https://github.com/foreverjs/forever/commit/c33f56e) fix critical bugs @v0.14.0 (`Tjatse`) 86 | * [545be49](https://github.com/foreverjs/forever/commit/545be49) [doc] Add docs badge to README (`René Föhring`) 87 | * [14bbf8c](https://github.com/foreverjs/forever/commit/14bbf8c) Fix links in readme (`jomo`) 88 | 89 | v0.14.0 / Tue, 30 Dec 2014 90 | ========================== 91 | * [477c460](https://github.com/foreverjs/forever/commit/477c460) [dist] Version bump. 0.14.0 (`indexzero`) 92 | * [b1158de](https://github.com/foreverjs/forever/commit/b1158de) Fixed typos. (`Sean Hussey`) 93 | * [cdfa701](https://github.com/foreverjs/forever/commit/cdfa701) [refactor] Tidy the logic for handling data back from monitor processes [fix text] Assert the correct things in test/core/stopbypid-peaceful-test.js [dist minor] Correct file headers in some test files [dist minor] s/if(/if (/, s/){/) {/, and other minor whitespace (`indexzero`) 94 | * [b678eb7](https://github.com/foreverjs/forever/commit/b678eb7) test cases for `stop peaceful` (`Tjatse`) 95 | * [c3baf77](https://github.com/foreverjs/forever/commit/c3baf77) if target is not a number, it could only be a script path, otherwise it is pid|uid|index|id (`Tjatse`) 96 | * [5c7ba63](https://github.com/foreverjs/forever/commit/5c7ba63) clean codes, and improve`findBy` performance (`Tjatse`) 97 | * [2c394ab](https://github.com/foreverjs/forever/commit/2c394ab) `forever stopbypid` is deprecated now, using `forever stop ` instead. (`Tjatse`) 98 | * [d506771](https://github.com/foreverjs/forever/commit/d506771) [fix] handle monitor error, and make `forever stopall` peaceful (`Tjatse`) 99 | * [ab8bcb8](https://github.com/foreverjs/forever/commit/ab8bcb8) ignore .idea on MAC (`Tjatse`) 100 | * [1308a96](https://github.com/foreverjs/forever/commit/1308a96) [ci] try and fix build (`Jarrett Cruger`) 101 | * [68502f1](https://github.com/foreverjs/forever/commit/68502f1) fix missing parameter (`peecky`) 102 | * [b85f8e2](https://github.com/foreverjs/forever/commit/b85f8e2) [dist fix] Added CHANGELOG.md again. Fixes #630. (`indexzero`) 103 | 104 | v0.13.0 / Tue, 4 Nov 2014 105 | ========================= 106 | * [8707877](https://github.com/foreverjs/forever/commit/8707877) [dist] Version bump. 0.13.0 (`indexzero`) 107 | * [3865596](https://github.com/foreverjs/forever/commit/3865596) [dist] Up-to-date linting with JSHint. Fixes #419. (`indexzero`) 108 | * [1d863ba](https://github.com/foreverjs/forever/commit/1d863ba) Renaming stoppid -> stopbypid (`Anthony Akentiev`) 109 | * [4adf834](https://github.com/foreverjs/forever/commit/4adf834) Little bug fix: comparing integers (`Anthony Akentiev`) 110 | * [c29de4b](https://github.com/foreverjs/forever/commit/c29de4b) README updated (`Anthony Akentiev`) 111 | * [54194df](https://github.com/foreverjs/forever/commit/54194df) stoppid command added to stop running under forever process by PID (`Anthony Akentiev`) 112 | * [c568f89](https://github.com/foreverjs/forever/commit/c568f89) [minor] Some small style changes to new(er) tests. (`indexzero`) 113 | * [8e4f1fb](https://github.com/foreverjs/forever/commit/8e4f1fb) code 0 should be treated as a Number too. (`Tjatse`) 114 | * [663e49a](https://github.com/foreverjs/forever/commit/663e49a) wait more... (`Tjatse`) 115 | * [1f184e8](https://github.com/foreverjs/forever/commit/1f184e8) test case for start/stop peaceful (`Tjatse`) 116 | * [8f7dfba](https://github.com/foreverjs/forever/commit/8f7dfba) [fix] relative script file should works fine, both with `start` or `stop`. (`Tjatse`) 117 | * [84cf5ad](https://github.com/foreverjs/forever/commit/84cf5ad) Add --workingDir option to specify the CWD of the process in which SCRIPT is run (`Myk Willis`) 118 | * [cb72aed](https://github.com/foreverjs/forever/commit/cb72aed) [dist] Update several dependencies to latest. (`indexzero`) 119 | 120 | v0.12.0 / Thu, 30 Oct 2014 121 | ========================== 122 | * [b01eabb](https://github.com/foreverjs/forever/commit/b01eabb) [dist] Version bump. 0.12.0 (`indexzero`) 123 | * [9b6c8f7](https://github.com/foreverjs/forever/commit/9b6c8f7) [dist] Assign things to the author and the contributors. (`indexzero`) 124 | * [af8d228](https://github.com/foreverjs/forever/commit/af8d228) fixes EACCESS error with .sock (UNIX domain sockets) on Windows. Uses named pipes instead. (`Miroslav Mocek`) 125 | * [eecf6a2](https://github.com/foreverjs/forever/commit/eecf6a2) improved error handling (`Kevin "Schmidty" Smith`) 126 | * [6707a40](https://github.com/foreverjs/forever/commit/6707a40) improved error handling (`Kevin "Schmidty" Smith`) 127 | * [a2320aa](https://github.com/foreverjs/forever/commit/a2320aa) [minor] Do not check for a variable twice. (`indexzero`) 128 | * [283f210](https://github.com/foreverjs/forever/commit/283f210) [refactor] Update to `forever-monitor@1.4.0` and do not use the deprecated `.options` option. You can see why it is deprecated. (`indexzero`) 129 | * [73359e8](https://github.com/foreverjs/forever/commit/73359e8) [doc] Make note that the new root is actually NOT the default since it looks like it could be. (`indexzero`) 130 | * [a74e87c](https://github.com/foreverjs/forever/commit/a74e87c) [fix] inherits configuration from parent process when using `startDaemon` method. - make variable names camelCasing (`Tjatse`) 131 | * [1f9b7f7](https://github.com/foreverjs/forever/commit/1f9b7f7) Test case of startDaemon() method - configuration inheritance issue. (`Tjatse`) 132 | * [1102d11](https://github.com/foreverjs/forever/commit/1102d11) [fix] inherits configuration from parent process when using `startDaemon` method. (`Tjatse`) 133 | * [487fc54](https://github.com/foreverjs/forever/commit/487fc54) An 'error' on stopall is not actually an error (`Ryan Angilly`) 134 | * [250a4f8](https://github.com/foreverjs/forever/commit/250a4f8) [fix doc] More documentation around `forever.startServer`. Fixes #566. (`indexzero`) 135 | * [dfed754](https://github.com/foreverjs/forever/commit/dfed754) [fix] Set `forever.root` and `forever.config.get(root)` for symmetry. (`indexzero`) 136 | * [9eeeeb1](https://github.com/foreverjs/forever/commit/9eeeeb1) [fix doc] Update documentation. Fixes #594. (`indexzero`) 137 | * [35f477f](https://github.com/foreverjs/forever/commit/35f477f) [fix] Update documentation for `forever.list`. Fixes #598. (`indexzero`) 138 | * [c21f55d](https://github.com/foreverjs/forever/commit/c21f55d) [doc fix] Document FOREVER_ROOT environment variable. Properly respect -p. Fixes #548. Fixes #541. Fixes #568. (`indexzero`) 139 | * [0f227e5](https://github.com/foreverjs/forever/commit/0f227e5) [dist] Remove `foreverd` from scripts. Fixes #581. (`indexzero`) 140 | * [5fb6329](https://github.com/foreverjs/forever/commit/5fb6329) [dist breaking api] Remove `forever.service`. Fixes #372. (`indexzero`) 141 | * [938bf33](https://github.com/foreverjs/forever/commit/938bf33) [fix] Properly boolean-ize `--killTree`. Fixes #579. (`indexzero`) 142 | * [45f321c](https://github.com/foreverjs/forever/commit/45f321c) [fix] Actually support the documented `--uid` or `-u` CLI option. Fixes #424. (`indexzero`) 143 | * [3a40761](https://github.com/foreverjs/forever/commit/3a40761) Added uid information to help usage as per README (`brianmarco`) 144 | * [fefce03](https://github.com/foreverjs/forever/commit/fefce03) fixed wrong usage for option fifo (`lulurun`) 145 | * [a216e76](https://github.com/foreverjs/forever/commit/a216e76) checks proc.running and writes STOPPED instead of uptime if stopped (`smoodiver`) 146 | * [55141c8](https://github.com/foreverjs/forever/commit/55141c8) Adds id parameter as outlined in https://github.com/nodejitsu/forever/issues/461. (`Jackson Gariety`) 147 | * [99ee565](https://github.com/foreverjs/forever/commit/99ee565) [dist] Bump to `forever-monitor@1.3.0` (`indexzero`) 148 | * [99cddb5](https://github.com/foreverjs/forever/commit/99cddb5) [dist] Added .jshintrc (`indexzero`) 149 | * [16b1013](https://github.com/foreverjs/forever/commit/16b1013) use SVG to display Travis CI build testing status (`Mithgol`) 150 | * [b4a8135](https://github.com/foreverjs/forever/commit/b4a8135) fixing a small typo in the 'e.g.' portion of request, whoops. (`Andrew Martin`) 151 | * [a248968](https://github.com/foreverjs/forever/commit/a248968) updating docs with the uid flag (`Andrew Martin`) 152 | * [f730407](https://github.com/foreverjs/forever/commit/f730407) [dist] v0.11.1 (`Julian Duque`) 153 | * [23a217c](https://github.com/foreverjs/forever/commit/23a217c) Fix remark from @julianduque (`Ignat Kolesnichenko`) 154 | * [7b20f0f](https://github.com/foreverjs/forever/commit/7b20f0f) Slightly better English for the 'restarting' messages (`Dan Dascalescu`) 155 | * [af83c0e](https://github.com/foreverjs/forever/commit/af83c0e) Allow to get logFile and pidFile from config (`Ignat Kolesnichenko`) 156 | * [2cb60e8](https://github.com/foreverjs/forever/commit/2cb60e8) Update cli.js (`Kevin Hill`) 157 | 158 | v0.11.0 / Thu, 10 Apr 2014 159 | ========================== 160 | * [09d8403](https://github.com/foreverjs/forever/commit/09d8403) [dist] Version bump. 0.11.0 (`Jarrett Cruger`) 161 | * [5e15626](https://github.com/foreverjs/forever/commit/5e15626) FIX: added FOREVER_ROOT variable (`srossross`) 162 | * [3cbabf4](https://github.com/foreverjs/forever/commit/3cbabf4) "forever start" hangs with node 0.11.9 (`jeromew`) 163 | * [7ff651b](https://github.com/foreverjs/forever/commit/7ff651b) Delete CHANGELOG.md (`Alexey Simonenko`) 164 | * [786271f](https://github.com/foreverjs/forever/commit/786271f) [dist] v0.10.11 (`Julian Duque`) 165 | * [7f4e4e9](https://github.com/foreverjs/forever/commit/7f4e4e9) [dist] Bump dependencies (`Julian Duque`) 166 | * [4822fec](https://github.com/foreverjs/forever/commit/4822fec) [fix] Trying to avoid the non-determinism in tests (`Julian Duque`) 167 | * [2e75aa1](https://github.com/foreverjs/forever/commit/2e75aa1) [fix] Add --killSignal to help (`Julian Duque`) 168 | * [b2b49d1](https://github.com/foreverjs/forever/commit/b2b49d1) [minor] Change order of option in help (`Julian Duque`) 169 | * [b0ec661](https://github.com/foreverjs/forever/commit/b0ec661) [dist] v0.10.10 (`Julian Duque`) 170 | * [bc48ca6](https://github.com/foreverjs/forever/commit/bc48ca6) [fix] Make vows happy (`Julian Duque`) 171 | * [2df789d](https://github.com/foreverjs/forever/commit/2df789d) Updated timespan to 2.1.0 (`Gabriel Petrovay`) 172 | * [70ab37e](https://github.com/foreverjs/forever/commit/70ab37e) Add --watchIgnore and colors (`Patrick Hogan`) 173 | * [a7d419c](https://github.com/foreverjs/forever/commit/a7d419c) Update README.md (`Jure`) 174 | * [2ba3158](https://github.com/foreverjs/forever/commit/2ba3158) Fixed watchIgnorePatterns assignment (`kbackowski`) 175 | * [acf59a7](https://github.com/foreverjs/forever/commit/acf59a7) Proper Revert "[fix] Make `-v|--version` work. Fixes #303." (`Maurycy Damian Wasilewski`) 176 | 177 | v0.10.9 / Tue, 15 Oct 2013 178 | ========================== 179 | * [bc55bbf](https://github.com/foreverjs/forever/commit/bc55bbf) [dist] Bump version to 0.10.9 (`Maciej Małecki`) 180 | * [b4b0541](https://github.com/foreverjs/forever/commit/b4b0541) [dist] Use `forever-monitor@1.2.3` (`Maciej Małecki`) 181 | 182 | v0.10.8 / Fri, 10 May 2013 183 | ========================== 184 | * [a4289d1](https://github.com/foreverjs/forever/commit/a4289d1) [dist] Bump version to 0.10.8 (`Maciej Małecki`) 185 | * [8afad64](https://github.com/foreverjs/forever/commit/8afad64) [ui dist] Output info about process being killed by signal (`Maciej Małecki`) 186 | 187 | v0.10.7 / Sat, 27 Apr 2013 188 | ========================== 189 | * [22a3923](https://github.com/foreverjs/forever/commit/22a3923) [dist] Version bump. 0.10.7 (`indexzero`) 190 | * [6440b4e](https://github.com/foreverjs/forever/commit/6440b4e) [fix] remove duplicate option (`Julian Duque`) 191 | 192 | v0.10.6 / Sun, 21 Apr 2013 193 | ========================== 194 | * [e8c48d4](https://github.com/foreverjs/forever/commit/e8c48d4) [dist] Version bump. 0.10.6 (`indexzero`) 195 | 196 | v0.10.5 / Sun, 21 Apr 2013 197 | ========================== 198 | * [a9d7aa1](https://github.com/foreverjs/forever/commit/a9d7aa1) [dist] Version bump. 0.10.5 (`indexzero`) 199 | * [1a1ba32](https://github.com/foreverjs/forever/commit/1a1ba32) [fix] Make `-v|--version` work. Fixes #303. (`indexzero`) 200 | * [10fa40f](https://github.com/foreverjs/forever/commit/10fa40f) [fix dist] Bump to `nssocket@0.10.0` to support `node@0.10.x`. Update travis to test it. Fixes #370. Fixes #400. (`indexzero`) 201 | * [bd42888](https://github.com/foreverjs/forever/commit/bd42888) [fix] Manually merge #405. Fixes #405. (`indexzero`) 202 | * [d3675fa](https://github.com/foreverjs/forever/commit/d3675fa) process exit on error (`Noah H. Smith`) 203 | * [b641a4a](https://github.com/foreverjs/forever/commit/b641a4a) [minor] Style compliance for #403. Fixes #403. (`indexzero`) 204 | * [477082b](https://github.com/foreverjs/forever/commit/477082b) add the --watchIgnore option to be able to ignore files or directories when --watch is enabled (`Stéphane Gully`) 205 | * [5fa39ce](https://github.com/foreverjs/forever/commit/5fa39ce) [fix] Return `monitor` from `.startDaemon()`. Fixes #387. Fixes #389. (`indexzero`) 206 | * [bda8604](https://github.com/foreverjs/forever/commit/bda8604) [fix] Manually merge `plain-feature` because of trailing space noise. Fixes #381. [dist] Bump dependencies (`indexzero`) 207 | * [6047462](https://github.com/foreverjs/forever/commit/6047462) [fix] Added the default `dir` column which outputs the sourceDir from `forever-monitor`. Fixes #367. (`indexzero`) 208 | * [9cbe4cb](https://github.com/foreverjs/forever/commit/9cbe4cb) [fix dist] Update to the latest `forever-monitor`. Fixes #361. (`indexzero`) 209 | * [055c483](https://github.com/foreverjs/forever/commit/055c483) [fix] Warn users if `--minUptime` or `--spinSleepTime` are not specified. Fixes #344. (`indexzero`) 210 | * [1e4b2f6](https://github.com/foreverjs/forever/commit/1e4b2f6) added and cli options for streaming log output, updated README.md and tests to reflect changes (`John Lancaster`) 211 | * [94f61f5](https://github.com/foreverjs/forever/commit/94f61f5) removed trailing whitespace from lib/forever.js and lib/forever/cli.js ☠ (`John Lancaster`) 212 | * [352947e](https://github.com/foreverjs/forever/commit/352947e) Update package.json (`Thomas`) 213 | * [e442ea9](https://github.com/foreverjs/forever/commit/e442ea9) add no process error handling to cli.restartAll (`Evan You`) 214 | * [d3ff4bd](https://github.com/foreverjs/forever/commit/d3ff4bd) Add timestamp support to forever log (`Julian Duque`) 215 | * [b999bc2](https://github.com/foreverjs/forever/commit/b999bc2) Support exit signal customization (comes from another commit to forever-monitor) (`Alexander Makarenko`) 216 | * [3feef60](https://github.com/foreverjs/forever/commit/3feef60) Use `path` option as forever root if given. (`filipovskii_off`) 217 | * [3496b64](https://github.com/foreverjs/forever/commit/3496b64) use process.env.USERPROFILE as alternative to process.env.HOME (for windows) (`ingmr`) 218 | * [2b2ebbc](https://github.com/foreverjs/forever/commit/2b2ebbc) Fix uids mistakenly taken for an id (`Jazz`) 219 | * [e52b063](https://github.com/foreverjs/forever/commit/e52b063) wrapped fs.unlinkSync in try-catch-block (`Felix Böhm`) 220 | * [33dc125](https://github.com/foreverjs/forever/commit/33dc125) added a helpful error message (`Felix Böhm`) 221 | * [f69eb4d](https://github.com/foreverjs/forever/commit/f69eb4d) Updated flatiron dependency to 0.2.8 (`Ian Babrou`) 222 | * [4e7fa8f](https://github.com/foreverjs/forever/commit/4e7fa8f) pid variable not use. (`Thomas Tourlourat`) 223 | * [5b7f30b](https://github.com/foreverjs/forever/commit/5b7f30b) don't remove log files (`Felix Böhm`) 224 | * [a73eb5a](https://github.com/foreverjs/forever/commit/a73eb5a) remove pid- & logfiles on `exit` and `stop` (`Felix Böhm`) 225 | * [70a6acd](https://github.com/foreverjs/forever/commit/70a6acd) [api] Accept --killTree from CLI (`indexzero`) 226 | * [777256f](https://github.com/foreverjs/forever/commit/777256f) Update lib/forever.js (`Bram Stein`) 227 | 228 | v0.10.1 / Sun, 8 Jul 2012 229 | ========================= 230 | * [4ed446f](https://github.com/foreverjs/forever/commit/4ed446f) [dist] Version bump. 0.10.1 (`indexzero`) 231 | * [df802d0](https://github.com/foreverjs/forever/commit/df802d0) [dist] Bump forever-monitor version (`indexzero`) 232 | 233 | v0.10.0 / Sun, 8 Jul 2012 234 | ========================= 235 | * [c8afac3](https://github.com/foreverjs/forever/commit/c8afac3) [dist] Version bump. 0.10.0 (`indexzero`) 236 | * [c2baf66](https://github.com/foreverjs/forever/commit/c2baf66) [minor] Prefer no spaces when declaring Array instances (`indexzero`) 237 | * [9823d13](https://github.com/foreverjs/forever/commit/9823d13) [fix] Ensure pidFile is written to disk (and updated on restart) by bin/monitor (`indexzero`) 238 | * [1dfe0d0](https://github.com/foreverjs/forever/commit/1dfe0d0) [dist] Update dependencies to hard versions (`indexzero`) 239 | * [6921e6c](https://github.com/foreverjs/forever/commit/6921e6c) [refactor minor] Final integrations for `forever-monitor@1.0.1` (`indexzero`) 240 | * [f27cdaa](https://github.com/foreverjs/forever/commit/f27cdaa) [doc] Remove documenetation specific to `forever-monitor` (`indexzero`) 241 | * [d9e5faa](https://github.com/foreverjs/forever/commit/d9e5faa) [fix] Remove require for unused `ps-tree` (`indexzero`) 242 | * [14e5bda](https://github.com/foreverjs/forever/commit/14e5bda) [dist] Only support node@0.8.x (`indexzero`) 243 | * [91bda36](https://github.com/foreverjs/forever/commit/91bda36) [refactor] Examples are now in `forever-monitor` (`indexzero`) 244 | * [c1f1e6f](https://github.com/foreverjs/forever/commit/c1f1e6f) [dist] Remove outdated docco docs (`indexzero`) 245 | * [b5ce548](https://github.com/foreverjs/forever/commit/b5ce548) [refactor] Finish refactor of core Monitor functionality into `forever-monitor` (`indexzero`) 246 | * [5225d68](https://github.com/foreverjs/forever/commit/5225d68) [refactor] Moved test/core/check-process-test.js into `forever-monitor` (`indexzero`) 247 | * [b46c4c0](https://github.com/foreverjs/forever/commit/b46c4c0) [refactor] Remove all code in `forever-monitor` (`indexzero`) 248 | * [a5343df](https://github.com/foreverjs/forever/commit/a5343df) [fix] Use process.execPath for spawning. (`Charlie McConnell`) 249 | * [4ed1beb](https://github.com/foreverjs/forever/commit/4ed1beb) [fix] Use process.execPath instead of a hashbang. (`Charlie McConnell`) 250 | * [4f72f8c](https://github.com/foreverjs/forever/commit/4f72f8c) [fix] Fix bad require path. (`Charlie McConnell`) 251 | * [665e1ec](https://github.com/foreverjs/forever/commit/665e1ec) [test] Temporary: prevent test failure from deprecation warning in core. (`Charlie McConnell`) 252 | * [1e8d7ca](https://github.com/foreverjs/forever/commit/1e8d7ca) [refactor] Remove unused fork-shim (`Charlie McConnell`) 253 | * [a1e8f21](https://github.com/foreverjs/forever/commit/a1e8f21) [test] Only test on node 0.8.x (`Charlie McConnell`) 254 | * [b7c303a](https://github.com/foreverjs/forever/commit/b7c303a) [refactor] Implement silent fork via spawn stdio options. (`Charlie McConnell`) 255 | * [4fed919](https://github.com/foreverjs/forever/commit/4fed919) [refactor] Refactor to remove daemon.node (`Charlie McConnell`) 256 | * [485a18b](https://github.com/foreverjs/forever/commit/485a18b) [dist] Remove microtime dependency (`Charlie McConnell`) 257 | * [45a7e51](https://github.com/foreverjs/forever/commit/45a7e51) [dist] Remove `node-fork` dependency (`Maciej Małecki`) 258 | * [ba6b76d](https://github.com/foreverjs/forever/commit/ba6b76d) [test] Remove test for `forkShim` option (`Maciej Małecki`) 259 | * [16d1419](https://github.com/foreverjs/forever/commit/16d1419) [refactor api] Start using native fork (`Maciej Małecki`) 260 | * [d000278](https://github.com/foreverjs/forever/commit/d000278) [docs] Add Travis CI badge to README. (`Charlie McConnell`) 261 | * [2e2d18a](https://github.com/foreverjs/forever/commit/2e2d18a) [test] Add .travis.yml for Travis CI. (`Charlie McConnell`) 262 | 263 | v0.9.2 / Mon, 11 Jun 2012 264 | ========================= 265 | * [02abd44](https://github.com/foreverjs/forever/commit/02abd44) [dist] Version bump v0.9.2 (`Charlie McConnell`) 266 | * [95d3e1a](https://github.com/foreverjs/forever/commit/95d3e1a) [minor] Remove unused argument. (`Charlie McConnell`) 267 | * [44490e6](https://github.com/foreverjs/forever/commit/44490e6) [test fix] Add missing .foreverignore test fixture. (`Charlie McConnell`) 268 | * [4245e54](https://github.com/foreverjs/forever/commit/4245e54) [fix] Update startOrRestart to fix bugs. (`Christian Howe`) 269 | * [592a1eb](https://github.com/foreverjs/forever/commit/592a1eb) Added `watchDirectory` to the list of options in README (to fulfill #271) (`Fedot Praslov`) 270 | * [cf5e5be](https://github.com/foreverjs/forever/commit/cf5e5be) [dist] Use daemon.node v0.5.x (`Charlie McConnell`) 271 | * [13ef52f](https://github.com/foreverjs/forever/commit/13ef52f) [dist] Fix maintainers field (`Christian Howe`) 272 | 273 | v0.9.1 / Sat, 5 May 2012 274 | ======================== 275 | * [75bfdab](https://github.com/foreverjs/forever/commit/75bfdab) [dist] Version bump v0.9.1 (`Charlie McConnell`) 276 | * [4116f85](https://github.com/foreverjs/forever/commit/4116f85) [fix] Pass argv options properly. (`Charlie McConnell`) 277 | * [44c2337](https://github.com/foreverjs/forever/commit/44c2337) closes #164 and #235 fix wrong usage of matchBase option of minimatch, use relative to watchDirectory path fore matching (`Oleg Slobodskoi`) 278 | * [2a7c477](https://github.com/foreverjs/forever/commit/2a7c477) Added watchDirectory to command line options (`Fedot Praslov`) 279 | * [8af6803](https://github.com/foreverjs/forever/commit/8af6803) [fix] Revert bad options commit. (`Charlie McConnell`) 280 | * [5d21f97](https://github.com/foreverjs/forever/commit/5d21f97) [fix] Fix unhandled `error` event in `forever stopall` (`Maciej Małecki`) 281 | * [49c2c47](https://github.com/foreverjs/forever/commit/49c2c47) [fix] Correct function name (`Maciej Małecki`) 282 | * [f3b119b](https://github.com/foreverjs/forever/commit/f3b119b) [dist] Version bump v0.9.0 (`Charlie McConnell`) 283 | * [b4798d8](https://github.com/foreverjs/forever/commit/b4798d8) [test fix] Make logger test more consistent. (`Charlie McConnell`) 284 | * [4848f90](https://github.com/foreverjs/forever/commit/4848f90) [test] Add test fixture for producing logging output. (`Charlie McConnell`) 285 | * [73b10be](https://github.com/foreverjs/forever/commit/73b10be) [test] New logging test for the new logging plugin. (`Charlie McConnell`) 286 | * [8ec0bce](https://github.com/foreverjs/forever/commit/8ec0bce) [fix] Restore stdout and stderr events, fix semantics of silent option. (`Charlie McConnell`) 287 | * [0b80e4d](https://github.com/foreverjs/forever/commit/0b80e4d) Minor wording fix (`Andrew Radev`) 288 | * [9c787df](https://github.com/foreverjs/forever/commit/9c787df) Stop or restart a process by its uid (`Andrew Radev`) 289 | * [af5b8c2](https://github.com/foreverjs/forever/commit/af5b8c2) [fix] cli pidFile text (`Bradley Meck`) 290 | * [1ad16b0](https://github.com/foreverjs/forever/commit/1ad16b0) [pull-request] #244, from @michaelcdillon (`Bradley Meck`) 291 | * [ea5317c](https://github.com/foreverjs/forever/commit/ea5317c) [doc] Remove unused `forever` option from docs (`Maciej Małecki`) 292 | * [8474c9c](https://github.com/foreverjs/forever/commit/8474c9c) [api] forkShim option should allow a string to say which module to use when shimming (rather than the one currently used by this process) (`Bradley Meck`) 293 | * [2f93ba4](https://github.com/foreverjs/forever/commit/2f93ba4) [fix] Destroy log file streams in a more intelligent way. (`Charlie McConnell`) 294 | * [89f3614](https://github.com/foreverjs/forever/commit/89f3614) [fix] Logging now survives child process restarts. (`Charlie McConnell`) 295 | * [2d7d462](https://github.com/foreverjs/forever/commit/2d7d462) [minor] Dont use optimist directly (`Joshua Holbrook`) 296 | * [cda371d](https://github.com/foreverjs/forever/commit/cda371d) [fix] Pass argvOptions to app.config.argv as well. (`Joshua Holbrook`) 297 | * [8529281](https://github.com/foreverjs/forever/commit/8529281) [refactor] Remove logging code from monitor. (`Charlie McConnell`) 298 | * [70ae4f4](https://github.com/foreverjs/forever/commit/70ae4f4) [refactor] Replace logging plugin. (`Charlie McConnell`) 299 | * [a6a1675](https://github.com/foreverjs/forever/commit/a6a1675) [fix] Remove duplicate alias. (`Charlie McConnell`) 300 | * [dd1508b](https://github.com/foreverjs/forever/commit/dd1508b) [fix] s/appendLog/append/g to make --append work. (`Charlie McConnell`) 301 | * [298ec73](https://github.com/foreverjs/forever/commit/298ec73) [fix] Restore optional logfile destination functionality. (`Charlie McConnell`) 302 | * [a0c9ac5](https://github.com/foreverjs/forever/commit/a0c9ac5) [fix] Restore self.warn method on monitor instance. (`Charlie McConnell`) 303 | * [114e378](https://github.com/foreverjs/forever/commit/114e378) [dist] Update package.json to use fork of daemon.node. (`Charlie McConnell`) 304 | * [8186994](https://github.com/foreverjs/forever/commit/8186994) [fix] Alter logging paths to reduce memory leakage and prevent stdio issues. (`Charlie McConnell`) 305 | * [5c8fcc5](https://github.com/foreverjs/forever/commit/5c8fcc5) [fix] Update forever.startDaemon to use adjusted daemon.node api. (`Charlie McConnell`) 306 | * [f44d5f4](https://github.com/foreverjs/forever/commit/f44d5f4) Fix worker crash from bad socket client (`Felix Geisendörfer`) 307 | * [b093bfc](https://github.com/foreverjs/forever/commit/b093bfc) [fix api] Expose `checkFile` and fix logical condition (`Maciej Małecki`) 308 | * [e154a50](https://github.com/foreverjs/forever/commit/e154a50) [fix] Pass options.argv instead of options (cli.js, line 188) (`Joshua Holbrook`) 309 | * [5aa16c3](https://github.com/foreverjs/forever/commit/5aa16c3) [dist] v0.8.5 (`Bradley Meck`) 310 | * [157ce7b](https://github.com/foreverjs/forever/commit/157ce7b) [fix] use env `bash` rather than bin/sh (`Bradley Meck`) 311 | * [205e6f3](https://github.com/foreverjs/forever/commit/205e6f3) [fix] EACCESS should still go to next() in `forever list` (`Bradley Meck`) 312 | 313 | v0.8.4 / Sun, 15 Jan 2012 314 | ========================= 315 | * [6094c7c](https://github.com/foreverjs/forever/commit/6094c7c) [dist] Version bump. 0.8.4 (`indexzero`) 316 | * [1f4f5dc](https://github.com/foreverjs/forever/commit/1f4f5dc) [fix test] Make test/monitor/fork-test.js idempotent for processes created (`indexzero`) 317 | * [b6daac5](https://github.com/foreverjs/forever/commit/b6daac5) [dist] `node-fork@0.4.x` (`indexzero`) 318 | * [92d7dee](https://github.com/foreverjs/forever/commit/92d7dee) [doc] Update examples/cli-multiple-start (`indexzero`) 319 | * [1fa4943](https://github.com/foreverjs/forever/commit/1fa4943) [refactor] Create unique worker socket files using the `microtime` module (`indexzero`) 320 | * [72dac45](https://github.com/foreverjs/forever/commit/72dac45) [fix] Update bad reference variable to forever in watch plugin (`indexzero`) 321 | 322 | v0.8.3 / Fri, 13 Jan 2012 323 | ========================= 324 | * [96277b7](https://github.com/foreverjs/forever/commit/96277b7) [dist] Version bump. 0.8.3. (`indexzero`) 325 | * [432a088](https://github.com/foreverjs/forever/commit/432a088) [fix] Allow for `forever set` to include values with `/` (i.e. directories) (`indexzero`) 326 | * [6bfe071](https://github.com/foreverjs/forever/commit/6bfe071) [fix test] try/catch around test/fixtures/* (`indexzero`) 327 | * [7064adb](https://github.com/foreverjs/forever/commit/7064adb) Show -a option when user met log file exist error. (`skyisle`) 328 | * [4e2ab81](https://github.com/foreverjs/forever/commit/4e2ab81) [fix] Don't leak `fs`, `path`, `nssocket`, `utile` and `forever` (`Maciej Małecki`) 329 | * [9b0ad25](https://github.com/foreverjs/forever/commit/9b0ad25) [fix] Don't leak `mkdirp` and `async` (`Maciej Małecki`) 330 | 331 | v0.8.2 / Fri, 6 Jan 2012 332 | ======================== 333 | * [6779342](https://github.com/foreverjs/forever/commit/6779342) [dist] Version bump. 0.8.2 (`indexzero`) 334 | * [6588f59](https://github.com/foreverjs/forever/commit/6588f59) [api test] Expose `.forkShim` for communicating between `0.6.x` and `0.4.x` processes (`indexzero`) 335 | * [82e2a7d](https://github.com/foreverjs/forever/commit/82e2a7d) [api refactor] Remove fork hack since we are now using `node-fork` (`indexzero`) 336 | * [a2c4313](https://github.com/foreverjs/forever/commit/a2c4313) [test fix] Fix test/worker/multiple-workers-test.js to pass on node@0.4.x and be idempotent (`indexzero`) 337 | * [63676ed](https://github.com/foreverjs/forever/commit/63676ed) [minor] Whitespace update (`indexzero`) 338 | * [a987826](https://github.com/foreverjs/forever/commit/a987826) [fix] Attempt to listen again if EADDRINUSE in forever.Worker (`indexzero`) 339 | * [d711ab8](https://github.com/foreverjs/forever/commit/d711ab8) [minor] Whitespace update (`indexzero`) 340 | 341 | v0.8.1 / Thu, 5 Jan 2012 342 | ======================== 343 | * [b15cd34](https://github.com/foreverjs/forever/commit/b15cd34) [dist] Version bump. 0.8.1 (`indexzero`) 344 | * [4e25765](https://github.com/foreverjs/forever/commit/4e25765) [fix] Print help on just `forever` (`indexzero`) 345 | * [0d5e893](https://github.com/foreverjs/forever/commit/0d5e893) [api] Added `forever restartall` and `forever.restartAll()`. Fixes #131 (`indexzero`) 346 | * [cef3435](https://github.com/foreverjs/forever/commit/cef3435) [doc fix] Update `.cleanup` to `.cleanUp`. Fixes #199 (`indexzero`) 347 | 348 | v0.8.0 / Thu, 5 Jan 2012 349 | ======================== 350 | * [53ba981](https://github.com/foreverjs/forever/commit/53ba981) [dist] Version bump. 0.8.0 (`indexzero`) 351 | * [7fc258c](https://github.com/foreverjs/forever/commit/7fc258c) [dist] Added @mmalecki to contributors (`indexzero`) 352 | * [93b3fd0](https://github.com/foreverjs/forever/commit/93b3fd0) [dist] Update node version to reflect backwards compatibility (`indexzero`) 353 | * [49de211](https://github.com/foreverjs/forever/commit/49de211) [dist test] Move test/fork-test.js to test/monitor/fork-test.js (`indexzero`) 354 | * [4ab4438](https://github.com/foreverjs/forever/commit/4ab4438) [fix] A couple of minor fixes to CLI edge cases (`indexzero`) 355 | * [b830218](https://github.com/foreverjs/forever/commit/b830218) [fix] Ensure `forever script.js` works (`indexzero`) 356 | * [285b659](https://github.com/foreverjs/forever/commit/285b659) [merge] Resolve bad cherry-pick from `fork` branch (`indexzero`) 357 | * [1f673f9](https://github.com/foreverjs/forever/commit/1f673f9) [fix] use node-fork for listing (`bradleymeck`) 358 | * [fa02258](https://github.com/foreverjs/forever/commit/fa02258) [fix] use node-fork so 0.6 can talk to 0.4 using the fork: true in combination with command (`bradleymeck`) 359 | * [b06d58b](https://github.com/foreverjs/forever/commit/b06d58b) [api] Expose `Monitor.fork` for using `child_process.fork()` (`indexzero`) 360 | * [2c6800a](https://github.com/foreverjs/forever/commit/2c6800a) [api] Expose `Monitor.fork` for using `child_process.fork()` (`indexzero`) 361 | * [7aa72c9](https://github.com/foreverjs/forever/commit/7aa72c9) [api test doc] Expose `.fork()` through forever for node-specific processes. Currently blocked by joyent/node#2454 (`indexzero`) 362 | * [1f78240](https://github.com/foreverjs/forever/commit/1f78240) [test minor] A couple of small updates for tests after recent API changes. Readd Worker.exitOnStop (`indexzero`) 363 | * [bde27e0](https://github.com/foreverjs/forever/commit/bde27e0) [refactor] Use the nssocket defined protocol for stopping and restarting worker processes (`indexzero`) 364 | * [dc0b457](https://github.com/foreverjs/forever/commit/dc0b457) [dist] Remove bin/forever-worker now that it `daemon.node` works again (`indexzero`) 365 | * [9cee338](https://github.com/foreverjs/forever/commit/9cee338) [wtf.node] BLACK VOODOO MAGIC. `daemon.node` somehow works even though libuv isnt fork(2)-safe (`indexzero`) 366 | * [ebd80a2](https://github.com/foreverjs/forever/commit/ebd80a2) [refactor] Attempt to spawn workers via bin/forever-worker. (`indexzero`) 367 | * [8f9f0ad](https://github.com/foreverjs/forever/commit/8f9f0ad) [refactor] Significant refactor to how forever works in the rewrite (`indexzero`) 368 | * [bca8ed9](https://github.com/foreverjs/forever/commit/bca8ed9) [test] Basic CLI test in `sh` (`Maciej Małecki`) 369 | * [a9247de](https://github.com/foreverjs/forever/commit/a9247de) [dist] Update `watch` to `watch@0.5` (`Maciej Małecki`) 370 | * [e57568b](https://github.com/foreverjs/forever/commit/e57568b) [test] Remove `cli` test (`Maciej Małecki`) 371 | * [9ff117d](https://github.com/foreverjs/forever/commit/9ff117d) [refactor] Move `daemon` to devDependencies on its way to deprecation (`indexzero`) 372 | * [84be160](https://github.com/foreverjs/forever/commit/84be160) [fix] Make logs work again (`Maciej Małecki`) 373 | * [d983726](https://github.com/foreverjs/forever/commit/d983726) [bin] Make `forever start` work with parameters (`Maciej Małecki`) 374 | * [55d96b2](https://github.com/foreverjs/forever/commit/55d96b2) [fix] Wrap parsing data from socket into `try .. catch` (`Maciej Małecki`) 375 | * [85c4542](https://github.com/foreverjs/forever/commit/85c4542) [minor] Remove unused `daemon` require (`Maciej Małecki`) 376 | * [321c182](https://github.com/foreverjs/forever/commit/321c182) [refactor] Replace `daemon.node` with `child_process.fork` (`Maciej Małecki`) 377 | * [df8d71d](https://github.com/foreverjs/forever/commit/df8d71d) [bin] Supress `stdout` and `stderr` when run as a fork (`Maciej Małecki`) 378 | * [2ead453](https://github.com/foreverjs/forever/commit/2ead453) [test] Test `kill` action (`Maciej Małecki`) 379 | * [a0d09d2](https://github.com/foreverjs/forever/commit/a0d09d2) [api] `kill` action for `Worker` (`Maciej Małecki`) 380 | * [6517f74](https://github.com/foreverjs/forever/commit/6517f74) [test] Add `MonitorMock.kill` (`Maciej Małecki`) 381 | * [883e712](https://github.com/foreverjs/forever/commit/883e712) [api] First pass at Worker integration (`Maciej Małecki`) 382 | * [bbc23e2](https://github.com/foreverjs/forever/commit/bbc23e2) [test] DRY tests a bit (`Maciej Małecki`) 383 | * [831f76f](https://github.com/foreverjs/forever/commit/831f76f) [api] Worker `spawn` command (`Maciej Małecki`) 384 | * [768f074](https://github.com/foreverjs/forever/commit/768f074) [api] If worker is a fork, notify master that it's listening (`Maciej Małecki`) 385 | * [cf716d5](https://github.com/foreverjs/forever/commit/cf716d5) [api] Guard for no options for Worker (`Maciej Małecki`) 386 | * [d174539](https://github.com/foreverjs/forever/commit/d174539) [test] Test if worker responds to `data` (`Maciej Małecki`) 387 | * [3059a9d](https://github.com/foreverjs/forever/commit/3059a9d) [api] Worker responds to `data` now (`Maciej Małecki`) 388 | * [e248716](https://github.com/foreverjs/forever/commit/e248716) [test] Add `data` property to `MonitorMock` (`Maciej Małecki`) 389 | * [748380b](https://github.com/foreverjs/forever/commit/748380b) [test] Don't hardcode socket path in tests (`Maciej Małecki`) 390 | * [d8b81dd](https://github.com/foreverjs/forever/commit/d8b81dd) [api] `Worker.start` calls back with socket path (`Maciej Małecki`) 391 | * [7be6917](https://github.com/foreverjs/forever/commit/7be6917) [test refactor] Restructure worker test a bit (`Maciej Małecki`) 392 | * [c710dc5](https://github.com/foreverjs/forever/commit/c710dc5) [test] Basic test for worker (`Maciej Małecki`) 393 | * [f06c345](https://github.com/foreverjs/forever/commit/f06c345) [api] Sketch of `Worker` (`Maciej Małecki`) 394 | * [34ccb24](https://github.com/foreverjs/forever/commit/34ccb24) [refactor] Remove watching code from `forever.Monitor` (`Maciej Małecki`) 395 | * [0e6ea8f](https://github.com/foreverjs/forever/commit/0e6ea8f) [test] Basic tests for `Logger` plugin (`Maciej Małecki`) 396 | * [f84634b](https://github.com/foreverjs/forever/commit/f84634b) [refactor] Add `Logger` plugin (`Maciej Małecki`) 397 | * [ab0f8e9](https://github.com/foreverjs/forever/commit/ab0f8e9) [refactor] Remove logging from `forever.Monitor` (`Maciej Małecki`) 398 | * [8a9af6b](https://github.com/foreverjs/forever/commit/8a9af6b) [refactor] Inherit from `broadway.App` (`Maciej Małecki`) 399 | * [d945bb2](https://github.com/foreverjs/forever/commit/d945bb2) [dist] Depend on `broadway` and `eventemitter2` (dev dep) (`Maciej Małecki`) 400 | * [cdb355f](https://github.com/foreverjs/forever/commit/cdb355f) [test] Add useful mocks (`Maciej Małecki`) 401 | * [ed75bd4](https://github.com/foreverjs/forever/commit/ed75bd4) [dist] Ignore vim swap files (`Maciej Małecki`) 402 | 403 | v0.7.6 / Fri, 23 Dec 2011 404 | ========================= 405 | * [2ac0459](https://github.com/foreverjs/forever/commit/2ac0459) [dist] Version bump. 0.7.6. 0.4.x only. `forever >= 0.8.0` will be 0.6.x compatible (`indexzero`) 406 | * [88d9c20](https://github.com/foreverjs/forever/commit/88d9c20) [dist] Remove clip dependency (`indexzero`) 407 | * [2815f71](https://github.com/foreverjs/forever/commit/2815f71) [fix] Break apart cli.logs to support `forever logs` and `forever logs ` correctly (`indexzero`) 408 | * [72f4d14](https://github.com/foreverjs/forever/commit/72f4d14) [test] Update test fixture pathing mistake (`indexzero`) 409 | * [c6072f5](https://github.com/foreverjs/forever/commit/c6072f5) [dist] Remove console.error/log statements (`indexzero`) 410 | * [ed0d1e8](https://github.com/foreverjs/forever/commit/ed0d1e8) [fix minor] Fix 2 typos in forever service CLI (`Maciej Małecki`) 411 | * [079137c](https://github.com/foreverjs/forever/commit/079137c) [refactor] Refactor Forever service CLI (`Maciej Małecki`) 412 | * [c01abef](https://github.com/foreverjs/forever/commit/c01abef) [api] Export `cli.getOptions` (`Maciej Małecki`) 413 | * [13e8db8](https://github.com/foreverjs/forever/commit/13e8db8) [api] Expose `argvOptions` (`Maciej Małecki`) 414 | * [ee9f98b](https://github.com/foreverjs/forever/commit/ee9f98b) [doc fix] `--pidfile` is now called `--pidFile` (`Maciej Małecki`) 415 | * [1d1656c](https://github.com/foreverjs/forever/commit/1d1656c) [test refactor] `test/{helpers.js => helpers/macros.js}` (`Maciej Małecki`) 416 | * [ce7d5a1](https://github.com/foreverjs/forever/commit/ce7d5a1) [fix] Fix option parsing for starting actions (`Maciej Małecki`) 417 | * [fc4dec5](https://github.com/foreverjs/forever/commit/fc4dec5) Fixed broken link, replaced indexzero with nodejitsu in url. (`Louis Galipeau`) 418 | * [0812449](https://github.com/foreverjs/forever/commit/0812449) [fix] Respect `-c` on restart. Fixes #159 (`indexzero`) 419 | * [0e7873b](https://github.com/foreverjs/forever/commit/0e7873b) [fix] Improve the ordering of options parsing and include some options missed on the reparse. Fixes #139 (`indexzero`) 420 | 421 | v0.7.5 / Fri, 2 Dec 2011 422 | ======================== 423 | * [76b4d96](https://github.com/foreverjs/forever/commit/76b4d96) [dist] Version bump. 0.7.5 (`indexzero`) 424 | * [d6c7590](https://github.com/foreverjs/forever/commit/d6c7590) [minor] Always try to parse the response before calling next() (`indexzero`) 425 | * [dcbfc70](https://github.com/foreverjs/forever/commit/dcbfc70) [dist] Various small esoteric changes. Fixes #179 (`indexzero`) 426 | * [061d14f](https://github.com/foreverjs/forever/commit/061d14f) [fix doc] Fix README to match flatiron refactor (`Maciej Małecki`) 427 | * [517d31b](https://github.com/foreverjs/forever/commit/517d31b) [fix] Make option aliases work again (`Maciej Małecki`) 428 | * [63d91b2](https://github.com/foreverjs/forever/commit/63d91b2) [fix] Fix for pass-through parameters (`nconf@0.5`) (`Maciej Małecki`) 429 | * [e7e8fdf](https://github.com/foreverjs/forever/commit/e7e8fdf) prevent leading dashes in autogenerated log/pid filenames (`Brian Mount`) 430 | * [76bea57](https://github.com/foreverjs/forever/commit/76bea57) [fix] Fix `require`s in `foreverd` (`Maciej Małecki`) 431 | * [7cdca07](https://github.com/foreverjs/forever/commit/7cdca07) [fix] Make it compatible with `broadway@0.1.1` (`nconf@0.5`) (`Maciej Małecki`) 432 | * [791c123](https://github.com/foreverjs/forever/commit/791c123) [dist] Locked in nconf to v0.4.x. Bumped to v0.7.4. Should close #172 (`Marak Squires`) 433 | * [4ae63d0](https://github.com/foreverjs/forever/commit/4ae63d0) [merge] A few random missed conflicts from `git cherry-pick` on 22 commits. oops. (`indexzero`) 434 | * [60a576a](https://github.com/foreverjs/forever/commit/60a576a) [test fix] Since forever.kill is async, use `async.forEach`. Update test/cli-test.js to rimraf ~/.forever temporarily (`indexzero`) 435 | * [1a04002](https://github.com/foreverjs/forever/commit/1a04002) [fix] Make `--help` work (`Maciej Małecki`) 436 | * [58c251f](https://github.com/foreverjs/forever/commit/58c251f) [fix] Make column operations work (`Maciej Małecki`) 437 | * [b9c5f18](https://github.com/foreverjs/forever/commit/b9c5f18) [refactor minor] Code formatting, unused variable (`Maciej Małecki`) 438 | * [feade6c](https://github.com/foreverjs/forever/commit/feade6c) [test] Basic CLI tests with some helpers (`Maciej Małecki`) 439 | * [d6b6c58](https://github.com/foreverjs/forever/commit/d6b6c58) [fix] Reset system store before reparsing argv (`Maciej Małecki`) 440 | * [736fecb](https://github.com/foreverjs/forever/commit/736fecb) [test] Clean up after tests are done (`Maciej Małecki`) 441 | * [6b1a08d](https://github.com/foreverjs/forever/commit/6b1a08d) [test] Add test for option parsing (`Maciej Małecki`) 442 | * [a52ee8a](https://github.com/foreverjs/forever/commit/a52ee8a) [refactor] Make `forever app.js` work (`Maciej Małecki`) 443 | * [93359eb](https://github.com/foreverjs/forever/commit/93359eb) [refactor doc] Document `cli.startDaemon` and `cli.cleanLogs` (`Maciej Małecki`) 444 | * [93482cb](https://github.com/foreverjs/forever/commit/93482cb) [refactor minor] Remove unused `tty` require (`Maciej Małecki`) 445 | * [4d3958e](https://github.com/foreverjs/forever/commit/4d3958e) [refactor] Better option parsing (`Maciej Małecki`) 446 | * [dde31b7](https://github.com/foreverjs/forever/commit/dde31b7) [refactor bin] Remove options parsing from bin (`Maciej Małecki`) 447 | * [d793874](https://github.com/foreverjs/forever/commit/d793874) [api] Remove redudant `forever` options (`Maciej Małecki`) 448 | * [c9ab4f0](https://github.com/foreverjs/forever/commit/c9ab4f0) [dist] Add `flatiron` dependency (`Maciej Małecki`) 449 | * [8abe38d](https://github.com/foreverjs/forever/commit/8abe38d) [refactor] Implement pass-through options for child (`Maciej Małecki`) 450 | * [b30316e](https://github.com/foreverjs/forever/commit/b30316e) [refactor] Use `utile.randomString` (`Maciej Małecki`) 451 | * [dbf46c3](https://github.com/foreverjs/forever/commit/dbf46c3) [refactor fix] Pass options to `forever.start` (`Maciej Małecki`) 452 | * [3d262df](https://github.com/foreverjs/forever/commit/3d262df) [refactor] Add `help` command (`Maciej Małecki`) 453 | * [1da249c](https://github.com/foreverjs/forever/commit/1da249c) [fix] Fix `cli.start` regex to match .* instead of .+ (`Maciej Małecki`) 454 | * [89969ef](https://github.com/foreverjs/forever/commit/89969ef) [refactor] First pass on flatiron refactor (`Maciej Małecki`) 455 | * [8b05686](https://github.com/foreverjs/forever/commit/8b05686) [dist] Depend on `utile` (`Maciej Małecki`) 456 | * [71cf0de](https://github.com/foreverjs/forever/commit/71cf0de) [test fix] Kill child in `forever-test.js` (`Maciej Małecki`) 457 | 458 | v0.7.3 / Thu, 17 Nov 2011 459 | ========================= 460 | * [865a8fd](https://github.com/foreverjs/forever/commit/865a8fd) [dist] Version bump. 0.7.3 (`indexzero`) 461 | * [7ab97bd](https://github.com/foreverjs/forever/commit/7ab97bd) always killTree (`Fabian Jakobs`) 462 | * [e4f2b09](https://github.com/foreverjs/forever/commit/e4f2b09) [dist] Update `watch` dependency. Fixes #155 (`indexzero`) 463 | * [5f20181](https://github.com/foreverjs/forever/commit/5f20181) [fix] give sigkills after a timeout given by options.killTTL in MS (`bradleymeck`) 464 | * [3f1ed35](https://github.com/foreverjs/forever/commit/3f1ed35) [test minor] Change `assert.length` to `assert.lengthOf` (`Maciej Małecki`) 465 | 466 | v0.7.2 / Sat, 22 Oct 2011 467 | ========================= 468 | * [382f8e7](https://github.com/foreverjs/forever/commit/382f8e7) [dist] Version bump. 0.7.2 (`indexzero`) 469 | * [9131af7](https://github.com/foreverjs/forever/commit/9131af7) [fix] Return when no index or script is passed to `forever logs`. Fixes #141 (`indexzero`) 470 | * [8176f9f](https://github.com/foreverjs/forever/commit/8176f9f) Make sure all data is streamed before we try to parse it. (`Mariusz Nowak`) 471 | * [4ca2862](https://github.com/foreverjs/forever/commit/4ca2862) [dist] Remove unnecessary eyes dependency (`indexzero`) 472 | * [74f3140](https://github.com/foreverjs/forever/commit/74f3140) [fix] Prefer `-` to `$` in `forever.randomString` (`indexzero`) 473 | * [684296a](https://github.com/foreverjs/forever/commit/684296a) [test] Test `checkProcess` (`Maciej Małecki`) 474 | * [c17d004](https://github.com/foreverjs/forever/commit/c17d004) [refactor] Make `forever.checkProcess` synchronous (`Maciej Małecki`) 475 | * [f820056](https://github.com/foreverjs/forever/commit/f820056) [fix] Use `process.kill` to check if process is alive (`Maciej Małecki`) 476 | 477 | v0.7.1 / Sun, 9 Oct 2011 478 | ======================== 479 | * [d791422](https://github.com/foreverjs/forever/commit/d791422) [dist] Verion bump. 0.7.1 (`indexzero`) 480 | * [0d4f68e](https://github.com/foreverjs/forever/commit/0d4f68e) [fix] Pass proc.spawnWith to `forever.restart`. Fixes #116 (`indexzero`) 481 | 482 | v0.7.0 / Sat, 8 Oct 2011 483 | ======================== 484 | * [39f8b5a](https://github.com/foreverjs/forever/commit/39f8b5a) [dist] Version bump. 0.7.0 (`indexzero`) 485 | * [0baaccf](https://github.com/foreverjs/forever/commit/0baaccf) [dist] Updated CHANGELOG.md (`indexzero`) 486 | * [91dbd32](https://github.com/foreverjs/forever/commit/91dbd32) [api test] Expose `this.spawnWith` in Monitor.data (`indexzero`) 487 | * [14c82fd](https://github.com/foreverjs/forever/commit/14c82fd) [dist] Update daemon to >= 0.3.2 (`indexzero`) 488 | * [e740fb6](https://github.com/foreverjs/forever/commit/e740fb6) [doc] Update README.md for `forever logs *` commands (`indexzero`) 489 | * [0d6f85f](https://github.com/foreverjs/forever/commit/0d6f85f) [api test] Added `forever logs` CLI commands and `forever.tail()` method with appropriate tests. Fixes #123, #93 (`indexzero`) 490 | * [3d23311](https://github.com/foreverjs/forever/commit/3d23311) [minor] Minor whitespace fix (`indexzero`) 491 | * [02f7b0f](https://github.com/foreverjs/forever/commit/02f7b0f) [dist] Update `test` command in package.json (`indexzero`) 492 | * [fa03117](https://github.com/foreverjs/forever/commit/fa03117) [fix] Add the child PID to the list from `psTree` not remove it (`indexzero`) 493 | * [7ae3d1d](https://github.com/foreverjs/forever/commit/7ae3d1d) [doc] Updated CHANGELOG.md (`indexzero`) 494 | * [7c82d4b](https://github.com/foreverjs/forever/commit/7c82d4b) [dist] Update contributors in package.json (`indexzero`) 495 | * [067d50c](https://github.com/foreverjs/forever/commit/067d50c) [minor] Remove file headers in examples/* (`indexzero`) 496 | * [a942985](https://github.com/foreverjs/forever/commit/a942985) [dist] Update Copyright to Nodejitsu Inc. (`indexzero`) 497 | * [877ef3b](https://github.com/foreverjs/forever/commit/877ef3b) [minor] Update file headers (`indexzero`) 498 | * [a61e6be](https://github.com/foreverjs/forever/commit/a61e6be) [dist] Updates for JSHint in bin/* (`indexzero`) 499 | * [f7575f9](https://github.com/foreverjs/forever/commit/f7575f9) [dist] Update for JSHint (`indexzero`) 500 | * [4e27e3d](https://github.com/foreverjs/forever/commit/4e27e3d) [api] Expose `Monitor.killTree` for killing process trees for processes spawned by forever (`indexzero`) 501 | * [a83a1e1](https://github.com/foreverjs/forever/commit/a83a1e1) kill all children of a monitored process. (`Dominic Tarr`) 502 | * [89be252](https://github.com/foreverjs/forever/commit/89be252) [refactor test dist] Refactor /lib/foreverd/ into /lib/forever/service/ (`indexzero`) 503 | * [36e0b9b](https://github.com/foreverjs/forever/commit/36e0b9b) [minor] Updated foreverd for JSHint (`indexzero`) 504 | * [3525130](https://github.com/foreverjs/forever/commit/3525130) [minor] Update lib/forever* for JSHint (`indexzero`) 505 | * [1390910](https://github.com/foreverjs/forever/commit/1390910) [fix] forgot to add adapters (`bradleymeck`) 506 | * [bad47f6](https://github.com/foreverjs/forever/commit/bad47f6) [fix][WIP] basic working order, starting CLI cleanup (`bradleymeck`) 507 | * [6f68823](https://github.com/foreverjs/forever/commit/6f68823) [API][WIP] Moved service manager out to its own system (`bradleymeck`) 508 | * [61651a7](https://github.com/foreverjs/forever/commit/61651a7) [fix] daemonize ourselve on startup rather than rely on OS function (TODO exit codes) (`bradleymeck`) 509 | * [782cca7](https://github.com/foreverjs/forever/commit/782cca7) [fix] services should be added to run levels during install (`bradleymeck`) 510 | * [f2026b3](https://github.com/foreverjs/forever/commit/f2026b3) [fix] service process listing (`bradleymeck`) 511 | * [1bfdcdb](https://github.com/foreverjs/forever/commit/1bfdcdb) [fix] Use lsb functions for starting up a daemon (`bradleymeck`) 512 | * [60d4329](https://github.com/foreverjs/forever/commit/60d4329) [fix] make services use hyphenated commands (`bradleymeck`) 513 | * [93053d6](https://github.com/foreverjs/forever/commit/93053d6) [api] Revive the service api stubs (`bradleymeck`) 514 | 515 | v0.6.9 / Tue, 4 Oct 2011 516 | ======================== 517 | * [620a362](https://github.com/foreverjs/forever/commit/620a362) [dist] Version bump. 0.6.9 (`indexzero`) 518 | * [2b8cf71](https://github.com/foreverjs/forever/commit/2b8cf71) [doc] Add `--plain` option to README (`Maciej Małecki`) 519 | * [4b08542](https://github.com/foreverjs/forever/commit/4b08542) [bin] Add `--plain` option disabling CLI colors (`Maciej Małecki`) 520 | 521 | v0.6.8 / Sat, 1 Oct 2011 522 | ======================== 523 | * [dfb12a6](https://github.com/foreverjs/forever/commit/dfb12a6) [dist] Version bump. 0.6.8 (`indexzero`) 524 | * [7d7398b](https://github.com/foreverjs/forever/commit/7d7398b) [doc] Update README.md with watch file options (`indexzero`) 525 | * [8c8f0e0](https://github.com/foreverjs/forever/commit/8c8f0e0) [fix minor] A couple of small changes to merge in watch from @mmalecki (`indexzero`) 526 | * [d891990](https://github.com/foreverjs/forever/commit/d891990) [test] Add tests for watch (`Maciej Małecki`) 527 | * [f636447](https://github.com/foreverjs/forever/commit/f636447) [test] Add fixtures for watch test (`Maciej Małecki`) 528 | * [836ea31](https://github.com/foreverjs/forever/commit/836ea31) [fix minor] Use `path.join` (`Maciej Małecki`) 529 | * [b9b3129](https://github.com/foreverjs/forever/commit/b9b3129) [fix refactor] Use `watch.watchTree` function (`Maciej Małecki`) 530 | * [1b02785](https://github.com/foreverjs/forever/commit/1b02785) [fix minor] Remove stupid `options.watch || false` (`Maciej Małecki`) 531 | * [7ababd6](https://github.com/foreverjs/forever/commit/7ababd6) [bin] Add --watch/-w command line option (`Maciej Małecki`) 532 | * [e2b3565](https://github.com/foreverjs/forever/commit/e2b3565) [api] Add watchDirectory option (`Maciej Małecki`) 533 | * [b9d9703](https://github.com/foreverjs/forever/commit/b9d9703) [api] Complete file watching with .foreverignore (`Maciej Małecki`) 534 | * [28a7c16](https://github.com/foreverjs/forever/commit/28a7c16) [dist] Add minimatch dependency (`Maciej Małecki`) 535 | * [fff672d](https://github.com/foreverjs/forever/commit/fff672d) [api] simplest possible file watcher (ref #41) (`Maciej Małecki`) 536 | * [d658ee3](https://github.com/foreverjs/forever/commit/d658ee3) [dist] add watch dependency (`Maciej Małecki`) 537 | 538 | v0.6.7 / Mon, 12 Sep 2011 539 | ========================= 540 | * [c87b4b3](https://github.com/foreverjs/forever/commit/c87b4b3) [dist] Version bump. 0.6.7 (`indexzero`) 541 | * [227b158](https://github.com/foreverjs/forever/commit/227b158) [refactor] replace sys module usages in examples with util (`Maciej Małecki`) 542 | * [8ae06c0](https://github.com/foreverjs/forever/commit/8ae06c0) [refactor test] replace sys module usages in tests with util (`Maciej Małecki`) 543 | * [72eba1f](https://github.com/foreverjs/forever/commit/72eba1f) [refactor] replace sys module usages with util (`Maciej Małecki`) 544 | * [00628c2](https://github.com/foreverjs/forever/commit/00628c2) [dist] Update winston version (`indexzero`) 545 | 546 | v0.6.6 / Sun, 28 Aug 2011 547 | ========================= 548 | * [3f3cd17](https://github.com/foreverjs/forever/commit/3f3cd17) [dist] Version bump. 0.6.6 (`indexzero`) 549 | * [735fc95](https://github.com/foreverjs/forever/commit/735fc95) [minor test] Update to the `hideEnv` implementation from @bmeck. Added tests appropriately (`indexzero`) 550 | * [52c0529](https://github.com/foreverjs/forever/commit/52c0529) [style] cleanup unused variable (`Bradley Meck`) 551 | * [03daece](https://github.com/foreverjs/forever/commit/03daece) [api] Add options.hideEnv {key:boolean_hide,} to hide default env values (`Bradley Meck`) 552 | 553 | v0.6.5 / Fri, 12 Aug 2011 554 | ========================= 555 | * [a3f0df5](https://github.com/foreverjs/forever/commit/a3f0df5) [dist] Version bump. 0.6.5 (`indexzero`) 556 | * [fdf15a0](https://github.com/foreverjs/forever/commit/fdf15a0) [api test] Update `forever.Monitor.prototype.restart()` to allow force restarting of processes in less than `.minUptime` (`indexzero`) 557 | 558 | v0.6.4 / Thu, 11 Aug 2011 559 | ========================= 560 | * [f308f7a](https://github.com/foreverjs/forever/commit/f308f7a) [dist] Version bump. 0.6.4 (`indexzero`) 561 | * [9dc7bad](https://github.com/foreverjs/forever/commit/9dc7bad) [doc] Added example about running / listing multiple processes programmatically (`indexzero`) 562 | * [c3fe93a](https://github.com/foreverjs/forever/commit/c3fe93a) [fix] Update forever.startServer() to support more liberal arguments (`indexzero`) 563 | 564 | v0.6.3 / Sat, 23 Jul 2011 565 | ========================= 566 | * [fa3b225](https://github.com/foreverjs/forever/commit/fa3b225) [dist] Version bump. 0.6.3 (`indexzero`) 567 | * [e47af9c](https://github.com/foreverjs/forever/commit/e47af9c) [fix] When stopping only respond with those processes which have been stopped. Fixes #87 (`indexzero`) 568 | * [e7b9e58](https://github.com/foreverjs/forever/commit/e7b9e58) [fix] Create `sockPath` if it does not exist already. Fixes #92 (`indexzero`) 569 | 570 | v0.6.2 / Tue, 19 Jul 2011 571 | ========================= 572 | * [845ce2c](https://github.com/foreverjs/forever/commit/845ce2c) [dist] Version bump. 0.6.2 (`indexzero`) 573 | * [f756e62](https://github.com/foreverjs/forever/commit/f756e62) [fix] Display warning / error messages to the user when contacting UNIX sockets. Fixes #88 (`indexzero`) 574 | 575 | v0.6.1 / Fri, 15 Jul 2011 576 | ========================= 577 | * [72f200b](https://github.com/foreverjs/forever/commit/72f200b) [dist] Version bump. 0.6.1 (`indexzero`) 578 | * [1c0792e](https://github.com/foreverjs/forever/commit/1c0792e) Process variables are not always available, for example if you execute forever with a different process like monit. (`Arnout Kazemier`) 579 | * [7ff26de](https://github.com/foreverjs/forever/commit/7ff26de) Fixed a bug where numbers in the file path caused forever to think that it should stop the script based on index instead of stopping it based on script. (`Arnout Kazemier`) 580 | 581 | v0.6.0 / Mon, 11 Jul 2011 582 | ========================= 583 | * [df54bc0](https://github.com/foreverjs/forever/commit/df54bc0) [dist] Version bump. 0.6.0 (`indexzero`) 584 | * [8a50cf6](https://github.com/foreverjs/forever/commit/8a50cf6) [doc] Minor updates to README.md (`indexzero`) 585 | * [1dac9f4](https://github.com/foreverjs/forever/commit/1dac9f4) [doc] Updated README.md (`indexzero`) 586 | * [9d35315](https://github.com/foreverjs/forever/commit/9d35315) [fix minor] Update how forever._debug works. Use updated CLI options in `forever restart` (`indexzero`) 587 | * [da86724](https://github.com/foreverjs/forever/commit/da86724) [doc] Regenerate docco docs (`indexzero`) 588 | * [ad40a95](https://github.com/foreverjs/forever/commit/ad40a95) [doc] Added some code docs (`indexzero`) 589 | * [221c170](https://github.com/foreverjs/forever/commit/221c170) [doc] Update help in bin/forever (`indexzero`) 590 | * [091e949](https://github.com/foreverjs/forever/commit/091e949) [api] Finished fleshing out `forever columns *` commands (`indexzero`) 591 | * [581a132](https://github.com/foreverjs/forever/commit/581a132) [fix] Update `forever cleanlogs` for 0.6.x (`indexzero`) 592 | * [a39fee1](https://github.com/foreverjs/forever/commit/a39fee1) [api] Began work on `forever columns *` (`indexzero`) 593 | * [381ecaf](https://github.com/foreverjs/forever/commit/381ecaf) [api] Expose `forever.columns` and update `forever.format` to generate results dynamically (`indexzero`) 594 | * [bc8153a](https://github.com/foreverjs/forever/commit/bc8153a) [minor] Trim whitespace in lib/* (`indexzero`) 595 | * [2a163d3](https://github.com/foreverjs/forever/commit/2a163d3) [dist] Add `portfinder` dependency to package.json (`indexzero`) 596 | * [57a5600](https://github.com/foreverjs/forever/commit/57a5600) [doc] Remove references to *.fvr files in README.md (`indexzero`) 597 | * [ef59672](https://github.com/foreverjs/forever/commit/ef59672) [test] Updated tests for refactor in previous commit (`indexzero`) 598 | * [7ae870e](https://github.com/foreverjs/forever/commit/7ae870e) [refactor] **Major awesome breaking changes** Forever no longer uses *.fvr files in-favor of a TCP server in each forever process started by the CLI. Programmatic usage will require an additional call to `forever.createServer()` explicitally in order for your application to be available in `forever list` or `forever.list()` (`indexzero`) 599 | * [a26cf9d](https://github.com/foreverjs/forever/commit/a26cf9d) [minor] Catch `uncaughtException` slightly more intelligently (`indexzero`) 600 | * [4446215](https://github.com/foreverjs/forever/commit/4446215) [api] Include uids in `forever list` (`indexzero`) 601 | * [57bc396](https://github.com/foreverjs/forever/commit/57bc396) [minor] Create `options.uid` by default in `.startDaemon()` if it is already not provided (`indexzero`) 602 | * [dbf4275](https://github.com/foreverjs/forever/commit/dbf4275) [api] Default `minUptime` to 0 (`indexzero`) 603 | * [079ca20](https://github.com/foreverjs/forever/commit/079ca20) [doc] Small update to README.md (`indexzero`) 604 | * [aaefc95](https://github.com/foreverjs/forever/commit/aaefc95) [fix] use default values for log file and pid file (prevents a process from being nuked by being daemonized) (`Bradley Meck`) 605 | * [76be51e](https://github.com/foreverjs/forever/commit/76be51e) [fix] Quick fix for the last commit (`indexzero`) 606 | * [6902890](https://github.com/foreverjs/forever/commit/6902890) [api test] Added generic hooks for forever.Monitor (`indexzero`) 607 | * [c7ff2d9](https://github.com/foreverjs/forever/commit/c7ff2d9) [doc] Update the help in the forever CLI and README.md (`indexzero`) 608 | * [725d11d](https://github.com/foreverjs/forever/commit/725d11d) [doc] Update README.md (`indexzero`) 609 | * [5a8b32e](https://github.com/foreverjs/forever/commit/5a8b32e) [doc] Regenerated docco docs (`indexzero`) 610 | * [dfb54be](https://github.com/foreverjs/forever/commit/dfb54be) [api test doc] Remove deprecated `forever.Forever` from samples and tests. Added `env` and `cwd` options and associated tests. Some additional code docs and minor style changes (`indexzero`) 611 | * [c5c9172](https://github.com/foreverjs/forever/commit/c5c9172) [api] Update `forever list` to use cliff (`indexzero`) 612 | * [d2aa52b](https://github.com/foreverjs/forever/commit/d2aa52b) [dist] Drop eyes in favor of cliff (`indexzero`) 613 | * [bc5995f](https://github.com/foreverjs/forever/commit/bc5995f) [fix minor] Keep processes silent on `forever restart` if requested. A couple of minor log formatting updates (`indexzero`) 614 | * [f11610e](https://github.com/foreverjs/forever/commit/f11610e) [minor api] Update to optional debugging. Various small style updates (`indexzero`) 615 | * [686d009](https://github.com/foreverjs/forever/commit/686d009) [minor api] Added forever.debug for debugging purposes (`indexzero`) 616 | * [abed353](https://github.com/foreverjs/forever/commit/abed353) [doc] Updated README.md with newer options and events (`indexzero`) 617 | * [da44ad0](https://github.com/foreverjs/forever/commit/da44ad0) [doc] Kill some ancient stuff in README.md (`indexzero`) 618 | * [3ef90c1](https://github.com/foreverjs/forever/commit/3ef90c1) [doc] Add a little more color to documentation for `forever.load()` (`indexzero`) 619 | * [3d6018f](https://github.com/foreverjs/forever/commit/3d6018f) [doc] Update documentation on forever.load(). Fixes #72 (`indexzero`) 620 | * [3c8e6eb](https://github.com/foreverjs/forever/commit/3c8e6eb) [api fix] When executing stopall, dont kill the current process. Refactor flow-control of forever.cleanUp() (`indexzero`) 621 | * [d681cb7](https://github.com/foreverjs/forever/commit/d681cb7) [fix] Dont allow `-` in uuids generated by forever. Fixes #66. (`indexzero`) 622 | * [e0c3dcf](https://github.com/foreverjs/forever/commit/e0c3dcf) [dist] Minor style updates. Update to use pkginfo (`indexzero`) 623 | 624 | v0.5.6 / Tue, 7 Jun 2011 625 | ======================== 626 | * [de0d6d2](https://github.com/foreverjs/forever/commit/de0d6d2) [dist] Version bump. 0.5.6 (`indexzero`) 627 | 628 | v0.5.5 / Tue, 31 May 2011 629 | ========================= 630 | * [4c5b73a](https://github.com/foreverjs/forever/commit/4c5b73a) [dist] Version bump. 0.5.5 (`indexzero`) 631 | * [1af1fe3](https://github.com/foreverjs/forever/commit/1af1fe3) [fix] Remove .fvr file when a forever.Monitor child exits (`indexzero`) 632 | 633 | v0.5.4 / Mon, 30 May 2011 634 | ========================= 635 | * [4e84d71](https://github.com/foreverjs/forever/commit/4e84d71) [dist] Version bump. 0.5.4 (`indexzero`) 636 | * [5b2bf74](https://github.com/foreverjs/forever/commit/5b2bf74) [test] Update test/multiple-processes-test.js so that it doesnt leave zombie processes behind (`indexzero`) 637 | * [6d93dcc](https://github.com/foreverjs/forever/commit/6d93dcc) Add --spinSleepTime to throttle instead of killing spinning scripts (`Dusty Leary`) 638 | 639 | v0.5.3 / Sun, 29 May 2011 640 | ========================= 641 | * [7634248](https://github.com/foreverjs/forever/commit/7634248) [dist] Version bump. 0.5.3 (`indexzero`) 642 | * [d6b0d0e](https://github.com/foreverjs/forever/commit/d6b0d0e) [test] Update tests to be consistent with new functionality (`indexzero`) 643 | * [921966a](https://github.com/foreverjs/forever/commit/921966a) [api] Improve forever when working with `-c` or `--command` (`indexzero`) 644 | * [349085d](https://github.com/foreverjs/forever/commit/349085d) [dist] Minor update to dependencies (`indexzero`) 645 | * [96c3f08](https://github.com/foreverjs/forever/commit/96c3f08) [dist] Update .gitignore for npm 1.0 (`indexzero`) 646 | * [f4982cd](https://github.com/foreverjs/forever/commit/f4982cd) [doc] Update README.md to still use -g (`indexzero`) 647 | * [3feb0bc](https://github.com/foreverjs/forever/commit/3feb0bc) [dist] Update package.json dependencies (`indexzero`) 648 | * [270d976](https://github.com/foreverjs/forever/commit/270d976) preferGlobal (`Dustin Diaz`) 649 | * [de90882](https://github.com/foreverjs/forever/commit/de90882) [doc] Update installation instructions with `-g` for npm 1.0 (`indexzero`) 650 | 651 | v0.5.2 / Fri, 13 May 2011 652 | ========================= 653 | * [2c99741](https://github.com/foreverjs/forever/commit/2c99741) [dist] Version bump. 0.5.2 (`indexzero`) 654 | * [eab1c04](https://github.com/foreverjs/forever/commit/eab1c04) [fix] Check if processes exist before returning in `.findByScript()`. Fixes #50 (`indexzero`) 655 | * [e18a256](https://github.com/foreverjs/forever/commit/e18a256) [fix] Batch the cleaning of *.fvr and *.pid files to avoid file descriptor overload. Fixes #53 (`indexzero`) 656 | * [828cd48](https://github.com/foreverjs/forever/commit/828cd48) [minor] *print help when a valid action isn't given (`nlco`) 657 | 658 | v0.5.1 / Sun, 1 May 2011 659 | ======================== 660 | * [f326d20](https://github.com/foreverjs/forever/commit/f326d20) [dist] Version bump. 0.5.1. Add `eyes` dependency (`indexzero`) 661 | 662 | v0.5.0 / Sun, 1 May 2011 663 | ======================== 664 | * [7b451d9](https://github.com/foreverjs/forever/commit/7b451d9) [dist] Version bump. 0.5.0 (`indexzero`) 665 | * [1511179](https://github.com/foreverjs/forever/commit/1511179) [doc] Regenerated docco docs (`indexzero`) 666 | * [0fb8abe](https://github.com/foreverjs/forever/commit/0fb8abe) [minor] Small require formatting updates. Try to be more future-proof. (`indexzero`) 667 | * [3112380](https://github.com/foreverjs/forever/commit/3112380) [fix] Small fixes found from some upstream integrations (`indexzero`) 668 | * [9788748](https://github.com/foreverjs/forever/commit/9788748) [fix] Better handling of bookkeeping of *.fvr and *.pid files. Closes #47 (`indexzero`) 669 | * [864b1d1](https://github.com/foreverjs/forever/commit/864b1d1) [minor] Small fixes (`indexzero`) 670 | * [9b56c41](https://github.com/foreverjs/forever/commit/9b56c41) [api] Allow for forced exit if scripts restart in less than `minUptime` (`indexzero`) 671 | * [650f874](https://github.com/foreverjs/forever/commit/650f874) [minor] Add docs for `forever clear ` (`indexzero`) 672 | * [396b9a1](https://github.com/foreverjs/forever/commit/396b9a1) [doc] Regenerate docco docs (`indexzero`) 673 | * [a49483d](https://github.com/foreverjs/forever/commit/a49483d) [doc] Updated README.md (`indexzero`) 674 | * [f0ba253](https://github.com/foreverjs/forever/commit/f0ba253) [bin api minor] Update Copyright headers. Refactor bin/forever into lib/forever/cli.js. Add `forever config`, `forever set `, and `forever clear ` (`indexzero`) 675 | * [dffd0d1](https://github.com/foreverjs/forever/commit/dffd0d1) [minor dist api] Small updates for storing a forever global config file. Update package.json using require-analyzer (`indexzero`) 676 | * [6741c3a](https://github.com/foreverjs/forever/commit/6741c3a) [minor] More work for multiple processes from a single programmatic usage (`indexzero`) 677 | * [6e52e03](https://github.com/foreverjs/forever/commit/6e52e03) [minor test] Added tests for multiple processes from a single node process (`indexzero`) 678 | * [1c16e81](https://github.com/foreverjs/forever/commit/1c16e81) [api test] Update to use nconf for forever configuration. Use uids for filenames instead of forever* and forever pids (more defensive + support for multiple monitors from a single `forever` process). (`indexzero`) 679 | * [be6de72](https://github.com/foreverjs/forever/commit/be6de72) [minor] Small updates after merging from kpdecker (`indexzero`) 680 | * [95434b3](https://github.com/foreverjs/forever/commit/95434b3) Proper pid lookup in getForeverId (`kpdecker`) 681 | * [13bf645](https://github.com/foreverjs/forever/commit/13bf645) Add custom root directory to the initd-example (For cases where /tmp is removed) (`kpdecker`) 682 | * [b181dd7](https://github.com/foreverjs/forever/commit/b181dd7) Init.d Example script (`kpdecker`) 683 | * [51bc6c0](https://github.com/foreverjs/forever/commit/51bc6c0) Append log implementation (`kpdecker`) 684 | * [588b2bf](https://github.com/foreverjs/forever/commit/588b2bf) Append log CLI (`kpdecker`) 685 | * [ab497f4](https://github.com/foreverjs/forever/commit/ab497f4) forever.stat append flag (`kpdecker`) 686 | * [dca33d8](https://github.com/foreverjs/forever/commit/dca33d8) CLI pidfile argument (`kpdecker`) 687 | * [52184ae](https://github.com/foreverjs/forever/commit/52184ae) forever.pidFilePath implementation (`kpdecker`) 688 | * [e9b2cd3](https://github.com/foreverjs/forever/commit/e9b2cd3) forever.logFilePath utility. Treat paths that start with / as paths relative to the root, not the forever root. (`kpdecker`) 689 | * [8e323ca](https://github.com/foreverjs/forever/commit/8e323ca) Pass cwd to spawn (`kpdecker`) 690 | * [b29a258](https://github.com/foreverjs/forever/commit/b29a258) Return non-zero error code on tryStart failure (`kpdecker`) 691 | * [11ffce8](https://github.com/foreverjs/forever/commit/11ffce8) Load the forever lib relative to the binary rather than using module notation. (`kpdecker`) 692 | 693 | v0.4.2 / Wed, 13 Apr 2011 694 | ========================= 695 | * [7089311](https://github.com/foreverjs/forever/commit/7089311) [dist] Version bump. 0.4.2 (`indexzero`) 696 | 697 | v0.4.1 / Sat, 19 Feb 2011 698 | ========================= 699 | * [f11321f](https://github.com/foreverjs/forever/commit/f11321f) [dist] Version bump. 0.4.1 (`indexzero`) 700 | * [987d8ed](https://github.com/foreverjs/forever/commit/987d8ed) [fix] Update sourceDir option to check for file paths relative to root (`indexzero`) 701 | 702 | v0.4.0 / Wed, 16 Feb 2011 703 | ========================= 704 | * [b870d47](https://github.com/foreverjs/forever/commit/b870d47) [dist] Version bump. 0.4.0 (`indexzero`) 705 | * [d9911dd](https://github.com/foreverjs/forever/commit/d9911dd) [doc] Update docs for v0.4.0 release (`indexzero`) 706 | * [6862ad5](https://github.com/foreverjs/forever/commit/6862ad5) [api] Expose options passed to child_process.spawn (`indexzero`) 707 | * [4b25241](https://github.com/foreverjs/forever/commit/4b25241) [doc] Added example for chroot (`indexzero`) 708 | * [9d2eefa](https://github.com/foreverjs/forever/commit/9d2eefa) [fix] Dont slice off arguments after [SCRIPT] if it is not passed to the CLI (e.g. forever list) (`indexzero`) 709 | * [7c0c3b8](https://github.com/foreverjs/forever/commit/7c0c3b8) [api] Refactor to use winston instead of pure sys.puts() for logging (`indexzero`) 710 | * [cc3d465](https://github.com/foreverjs/forever/commit/cc3d465) [api] Make forever.load() sync and not required for default configurations. Grossly simplifies saving / reloading semantics (`indexzero`) 711 | * [fd1b9a6](https://github.com/foreverjs/forever/commit/fd1b9a6) [api] Added `restart` command to both forever.Monitor and CLI (`indexzero`) 712 | * [c073c47](https://github.com/foreverjs/forever/commit/c073c47) [api] First pass at "restart" functionality, not 100% yet (`indexzero`) 713 | * [7b9b4be](https://github.com/foreverjs/forever/commit/7b9b4be) [docs] Updated docs from docco (`indexzero`) 714 | * [ea89def](https://github.com/foreverjs/forever/commit/ea89def) [minor] Small formatting update to package.json (`indexzero`) 715 | * [85b0a02](https://github.com/foreverjs/forever/commit/85b0a02) [api] Added ctime property to forever instances to track uptime (`indexzero`) 716 | * [bc07f95](https://github.com/foreverjs/forever/commit/bc07f95) [docs refactor] Refactor forever.Forever into lib/forever/monitor.js (`indexzero`) 717 | 718 | v0.3.5 / Fri, 11 Feb 2011 719 | ========================= 720 | * [884037a](https://github.com/foreverjs/forever/commit/884037a) [dist] Version bump. 0.3.5. depends on daemon > 0.3.0 & node > 0.4.0 (`indexzero`) 721 | * [7b31da2](https://github.com/foreverjs/forever/commit/7b31da2) [api minor] Updates for daemon.node 0.2.0. Fix randomString so it doesnt generate strings with "/" (`indexzero`) 722 | * [a457ab7](https://github.com/foreverjs/forever/commit/a457ab7) [doc] Add docs from docco (`indexzero`) 723 | * [4a0ca64](https://github.com/foreverjs/forever/commit/4a0ca64) expose command to bin/forever as an option (`Adrien Friggeri`) 724 | 725 | v0.3.1 / Fri, 24 Dec 2010 726 | ========================= 727 | * [3c7e4a7](https://github.com/foreverjs/forever/commit/3c7e4a7) [dist doc] Version bump 0.3.1. Added CHANGELOG.md (`indexzero`) 728 | * [38177c4](https://github.com/foreverjs/forever/commit/38177c4) [bin] Ensure both daemons and long running processes get the same stat checking (`indexzero`) 729 | * [ea6849d](https://github.com/foreverjs/forever/commit/ea6849d) [api] Make it the responsibility of the programmer to save/re-save the Forever information on start or restart events (`indexzero`) 730 | * [14c7aa8](https://github.com/foreverjs/forever/commit/14c7aa8) [api test bin doc] Added stop by script name feature. Improved the cleanlogs functionality. Made event emission consistent. Added to docs (`indexzero`) 731 | * [b7f792b](https://github.com/foreverjs/forever/commit/b7f792b) [minor] Small update to how forever works with pid files (`indexzero`) 732 | * [57850e9](https://github.com/foreverjs/forever/commit/57850e9) [api fix] Improved the way forever manages pid / fvr files. Added cleanlogs command line option (`indexzero`) 733 | * [070313e](https://github.com/foreverjs/forever/commit/070313e) [api] Push options hierarchy up one level. e.g. Forever.options.silent is now Forever.silent (`indexzero`) 734 | * [124cc25](https://github.com/foreverjs/forever/commit/124cc25) [fix api bin test] Check for scripts with fs.stat() before running them. Use process.kill instead of exec('kill'). Clean logs from command line. Display log file in forever list. Emit save event. (`indexzero`) 735 | * [57273ea](https://github.com/foreverjs/forever/commit/57273ea) updated the readme with non-node usage and an example (`James Halliday`) 736 | * [cc33f06](https://github.com/foreverjs/forever/commit/cc33f06) passing test for non-node array usage (`James Halliday`) 737 | * [761b31b](https://github.com/foreverjs/forever/commit/761b31b) file array case shortcut to set the command and options (`James Halliday`) 738 | * [02de53f](https://github.com/foreverjs/forever/commit/02de53f) "command" option to spawn() with, defaults to "node" (`James Halliday`) 739 | * [6feedc1](https://github.com/foreverjs/forever/commit/6feedc1) [minor] Remove unnecessary comma in package.json (`indexzero`) 740 | 741 | v0.3.0 / Tue, 23 Nov 2010 742 | ========================= 743 | * [5d6f8da](https://github.com/foreverjs/forever/commit/5d6f8da) [dist] Version bump. 0.3.0 (`indexzero`) 744 | * [29bff87](https://github.com/foreverjs/forever/commit/29bff87) [doc] Updated formatting in README.md (`indexzero`) 745 | * [00fc643](https://github.com/foreverjs/forever/commit/00fc643) [api bin doc test] Added stop, stopall, and list command line functionality. Forever now tracks all daemons running on the system using *.fvr files (`indexzero`) 746 | * [d084ad1](https://github.com/foreverjs/forever/commit/d084ad1) [minor] Make samples/server.js listen on 8000 (`indexzero`) 747 | 748 | v0.2.7 / Tue, 16 Nov 2010 749 | ========================= 750 | * [29bc24f](https://github.com/foreverjs/forever/commit/29bc24f) [minor] Version bump. Fix small bug in 0.2.6 (`indexzero`) 751 | 752 | v0.2.6 / Mon, 15 Nov 2010 753 | ========================= 754 | * [2bcc53d](https://github.com/foreverjs/forever/commit/2bcc53d) [bin dist] Version bump. Small fixes from 0.2.5 (`indexzero`) 755 | * [faacc0f](https://github.com/foreverjs/forever/commit/faacc0f) [doc] Typo (`indexzero`) 756 | 757 | v0.2.5 / Sun, 14 Nov 2010 758 | ========================= 759 | * [0d5a789](https://github.com/foreverjs/forever/commit/0d5a789) [dist] Version bump. (`indexzero`) 760 | * [04705ed](https://github.com/foreverjs/forever/commit/04705ed) [api test bin dist] Update to use daemon.node (`indexzero`) 761 | * [65a91fb](https://github.com/foreverjs/forever/commit/65a91fb) [minor] Added .gitignore (`indexzero`) 762 | 763 | v0.2.0 / Mon, 27 Sep 2010 764 | ========================= 765 | * [f916359](https://github.com/foreverjs/forever/commit/f916359) [minor dist] Added LICENSE. Refactor forever.js to be more DRY (`indexzero`) 766 | * [9243dee](https://github.com/foreverjs/forever/commit/9243dee) Removed repeating function and replaced it by template generator (`Fedor Indutny`) 767 | * [347dcaa](https://github.com/foreverjs/forever/commit/347dcaa) [minor] Updated contributors (`indexzero`) 768 | * [a4f1700](https://github.com/foreverjs/forever/commit/a4f1700) [api test doc dist] Version bump. Merged from donnerjack. Added ability to log to file(s). Updated docs. (`indexzero`) 769 | * [d5d2f1d](https://github.com/foreverjs/forever/commit/d5d2f1d) New-line at the end of file (`Fedor Indutny`) 770 | * [73b52a4](https://github.com/foreverjs/forever/commit/73b52a4) Added chaining to run, simplyfied exports.run (`Fedor Indutny`) 771 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2010 Charlie Robbins & the Contributors 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # forever 2 | 3 | [![Join the chat at https://gitter.im/foreverjs/forever](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/foreverjs/forever?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 4 | 5 | [![Version npm](https://img.shields.io/npm/v/forever.svg?style=flat-square)](https://www.npmjs.com/package/forever)[![npm Downloads](https://img.shields.io/npm/dm/forever.svg?style=flat-square)](https://www.npmjs.com/package/forever)[![Build Status](https://img.shields.io/travis/foreverjs/forever/master.svg?style=flat-square)](https://travis-ci.org/foreverjs/forever)[![Dependencies](https://img.shields.io/david/foreverjs/forever.svg?style=flat-square)](https://david-dm.org/foreverjs/forever)[![Inline docs](http://inch-ci.org/github/foreverjs/forever.svg?branch=master)](http://inch-ci.org/github/foreverjs/forever) 6 | 7 | [![NPM](https://nodei.co/npm/forever.png?downloads=true&downloadRank=true)](https://nodei.co/npm/forever/) 8 | 9 | 10 | A simple CLI tool for ensuring that a given script runs continuously (i.e. forever). 11 | Note that this project currently fully depends on the community for implementing fixes and new features. For new installations we encourage you to use [pm2](https://pm2.keymetrics.io/) or [nodemon](https://nodemon.io/) 12 | 13 | ## Installation 14 | 15 | ``` bash 16 | $ [sudo] npm install forever -g 17 | ``` 18 | 19 | **Note:** If you are using forever _programmatically_ you should install [forever-monitor][0]. 20 | 21 | ``` bash 22 | $ cd /path/to/your/project 23 | $ [sudo] npm install forever-monitor 24 | ``` 25 | 26 | ## Usage 27 | There are two ways to use forever: through the command line or by using forever in your code. **Note:** If you are using forever _programatically_ you should install [forever-monitor][0]. 28 | 29 | ### Command Line Usage 30 | You can use forever to run scripts continuously (whether it is written in node.js or not). 31 | 32 | **Example** 33 | ``` 34 | forever start app.js 35 | ``` 36 | 37 | **Options** 38 | ``` 39 | $ forever --help 40 | usage: forever [action] [options] SCRIPT [script-options] 41 | 42 | Monitors the script specified in the current process or as a daemon 43 | 44 | actions: 45 | start Start SCRIPT as a daemon 46 | stop Stop the daemon SCRIPT by Id|Uid|Pid|Index|Script 47 | stopall Stop all running forever scripts 48 | restart Restart the daemon SCRIPT 49 | restartall Restart all running forever scripts 50 | list List all running forever scripts 51 | config Lists all forever user configuration 52 | set Sets the specified forever config 53 | clear Clears the specified forever config 54 | logs Lists log files for all forever processes 55 | logs Tails the logs for 56 | columns add Adds the specified column to the output in `forever list`. Supported columns: 'uid', 'command', 'script', 'forever', 'pid', 'id', 'logfile', 'uptime' 57 | columns rm Removed the specified column from the output in `forever list` 58 | columns set Set all columns for the output in `forever list` 59 | columns reset Resets all columns to defaults for the output in `forever list` 60 | cleanlogs [CAREFUL] Deletes all historical forever log files 61 | 62 | options: 63 | -m MAX Only run the specified script MAX times 64 | -l LOGFILE Logs the forever output to LOGFILE 65 | -o OUTFILE Logs stdout from child script to OUTFILE 66 | -e ERRFILE Logs stderr from child script to ERRFILE 67 | -p PATH Base path for all forever related files (pid files, etc.) 68 | -c COMMAND COMMAND to execute (defaults to node) 69 | -a, --append Append logs 70 | -f, --fifo Stream logs to stdout 71 | -n, --number Number of log lines to print 72 | --pidFile The pid file 73 | --uid DEPRECATED. Process uid, useful as a namespace for processes (must wrap in a string) 74 | e.g. forever start --uid "production" app.js 75 | forever stop production 76 | --id DEPRECATED. Process id, similar to uid, useful as a namespace for processes (must wrap in a string) 77 | e.g. forever start --id "test" app.js 78 | forever stop test 79 | --sourceDir The source directory for which SCRIPT is relative to 80 | --workingDir The working directory in which SCRIPT will execute 81 | --minUptime Minimum uptime (millis) for a script to not be considered "spinning" 82 | --spinSleepTime Time to wait (millis) between launches of a spinning script. 83 | --colors --no-colors will disable output coloring 84 | --plain Disable command line colors 85 | -d, --debug Forces forever to log debug output 86 | -v, --verbose Turns on the verbose messages from Forever 87 | -s, --silent Run the child script silencing stdout and stderr 88 | -w, --watch Watch for file changes 89 | --watchDirectory Top-level directory to watch from 90 | --watchIgnore To ignore pattern when watch is enabled (multiple option is allowed) 91 | -t, --killTree Kills the entire child process tree on `stop` 92 | --killSignal Support exit signal customization (default is SIGKILL), 93 | used for restarting script gracefully e.g. --killSignal=SIGTERM 94 | Any console output generated after calling `forever stop/stopall` will not appear in the logs 95 | -h, --help You're staring at it 96 | 97 | [Long Running Process] 98 | The forever process will continue to run outputting log messages to the console. 99 | ex. forever -o out.log -e err.log my-script.js 100 | 101 | [Daemon] 102 | The forever process will run as a daemon which will make the target process start 103 | in the background. This is extremely useful for remote starting simple node.js scripts 104 | without using nohup. It is recommended to run start with -o -l, & -e. 105 | ex. forever start -l forever.log -o out.log -e err.log my-daemon.js 106 | forever stop my-daemon.js 107 | ``` 108 | 109 | There are [several examples][1] designed to test the fault tolerance of forever. Here's a simple usage example: 110 | 111 | ``` bash 112 | $ forever -m 5 examples/error-on-timer.js 113 | ``` 114 | 115 | ### JSON Configuration Files 116 | 117 | In addition to passing forever the path to a script (along with accompanying options, described above), you may also pass forever the path to a JSON file containing these options. For example, consider an application with the following file structure: 118 | 119 | ``` 120 | . 121 | ├── forever 122 | │ └── development.json 123 | └── index.js 124 | 125 | // forever/development.json 126 | { 127 | // Comments are supported 128 | "uid": "app", 129 | "append": true, 130 | "watch": true, 131 | "script": "index.js", 132 | "sourceDir": "/home/myuser/app", 133 | "logFile": "/home/myuser/logs/forever.log", 134 | "outFile": "/home/myuser/logs/out.log", 135 | "errFile": "/home/myuser/logs/error.log" 136 | } 137 | ``` 138 | 139 | This application could be started with forever, as shown below: 140 | 141 | ``` bash 142 | $ forever start ./forever/development.json 143 | ``` 144 | 145 | Absolute paths to such configuration files are also supported: 146 | 147 | ``` bash 148 | $ forever start /home/myuser/app/forever/development.json 149 | ``` 150 | 151 | **Note:** Forever parses JSON configuration files using [shush](https://github.com/krakenjs/shush), allowing the use of in-line comments within such files. 152 | 153 | #### Multi-App Configuration Files 154 | 155 | JSON configuration files can also be used to define the startup options for *multiple* applications, as shown below. 156 | 157 | ``` 158 | [ 159 | { 160 | // App1 161 | "uid": "app1", 162 | "append": true, 163 | "watch": true, 164 | "script": "index.js", 165 | "sourceDir": "/home/myuser/app1" 166 | }, 167 | { 168 | // App2 169 | "uid": "app2", 170 | "append": true, 171 | "watch": true, 172 | "script": "index.js", 173 | "sourceDir": "/home/myuser/app2", 174 | "args": ["--port", "8081"] 175 | } 176 | ] 177 | ``` 178 | 179 | ### Using In Your Code 180 | The forever module exposes some useful methods to use in your code. Each method returns an instance of an EventEmitter which emits when complete. See the [forever cli commands][2] for sample usage. 181 | 182 | **Remark:** As of `forever@0.6.0` processes will not automatically be available in `forever.list()`. In order to get your processes into `forever.list()` or `forever list` you must instantiate the `forever` socket server: 183 | 184 | ``` js 185 | forever.startServer(child); 186 | ``` 187 | 188 | This method takes multiple `forever.Monitor` instances which are defined in the `forever-monitor` dependency. 189 | 190 | #### forever.load (config) 191 | _Synchronously_ sets the specified configuration (config) for the forever module. There are two important options: 192 | 193 | Option | Description   | Default 194 | ------- | ------------------------------------------------- | --------- 195 | root | Directory to put all default forever log files | `forever.root` 196 | pidPath | Directory to put all forever *.pid files | `[root]/pids` 197 | sockPath | Directory for sockets for IPC between workers | `[root]/sock` 198 | loglength | Number of logs to return in `forever tail` | 100 199 | columns | Array of columns to display when `format` is true | `forever.config.get('columns')` 200 | debug | Boolean value indicating to run in debug mode | false 201 | stream | Boolean value indicating if logs will be streamed | false 202 | 203 | #### forever.start (file, options) 204 | Starts a script with forever. The `options` object is what is expected by the `Monitor` of `forever-monitor`. 205 | 206 | #### forever.startDaemon (file, options) 207 | Starts a script with forever as a daemon. WARNING: Will daemonize the current process. The `options` object is what is expected by the `Monitor` of `forever-monitor`. 208 | 209 | #### forever.stop (index) 210 | Stops the forever daemon script at the specified index. These indices are the same as those returned by forever.list(). This method returns an EventEmitter that raises the 'stop' event when complete. 211 | 212 | #### forever.stopAll (format) 213 | Stops all forever scripts currently running. This method returns an EventEmitter that raises the 'stopAll' event when complete. 214 | 215 | The `format` parameter is a boolean value indicating whether the returned values should be formatted according to the configured columns which can set with `forever columns` or programmatically `forever.config.set('columns')`. 216 | 217 | #### forever.list (format, callback) 218 | Returns a list of metadata objects about each process that is being run using forever. This method will return the list of metadata as such. Only processes which have invoked `forever.startServer()` will be available from `forever.list()` 219 | 220 | The `format` parameter is a boolean value indicating whether the returned values should be formatted according to the configured columns which can set with `forever columns` or programmatically `forever.config.set('columns')`. 221 | 222 | #### forever.tail (target, options, callback) 223 | Responds with the logs from the target script(s) from `tail`. There are two options: 224 | 225 | * `length` (numeric): is is used as the `-n` parameter to `tail`. 226 | * `stream` (boolean): is is used as the `-f` parameter to `tail`. 227 | 228 | #### forever.cleanUp () 229 | Cleans up any extraneous forever *.pid files that are on the target system. This method returns an EventEmitter that raises the 'cleanUp' event when complete. 230 | 231 | #### forever.cleanLogsSync (processes) 232 | Removes all log files from the root forever directory that do not belong to current running forever processes. Processes are the value returned from `Monitor.data` in `forever-monitor`. 233 | 234 | #### forever.startServer (monitor0, monitor1, ..., monitorN) 235 | Starts the `forever` HTTP server for communication with the forever CLI. **NOTE:** This will change your `process.title`. This method takes multiple `forever.Monitor` instances which are defined in the `forever-monitor` dependency. 236 | 237 | ### Logging and output file locations 238 | 239 | By default `forever` places all of the files it needs into `/$HOME/.forever`. If you would like to change that location just set the `FOREVER_ROOT` environment variable when you are running forever: 240 | 241 | ``` 242 | FOREVER_ROOT=/etc/forever forever start index.js 243 | ``` 244 | 245 | Make sure that the user running the process has the appropriate privileges to read & write to this directory. 246 | 247 | ## Run Tests 248 | 249 | ``` bash 250 | $ npm test 251 | ``` 252 | 253 | #### License: MIT 254 | #### Author: [Charlie Robbins](https://github.com/indexzero) 255 | #### Maintainer: [Igor Savin](https://github.com/kibertoad) 256 | #### Contributors: [Fedor Indutny](https://github.com/indutny), [James Halliday](http://substack.net/), [Charlie McConnell](https://github.com/avianflu), [Maciej Malecki](https://github.com/mmalecki), [John Lancaster](http://jlank.com) 257 | 258 | [0]: https://github.com/foreverjs/forever-monitor 259 | [1]: https://github.com/foreverjs/forever-monitor/tree/master/examples 260 | [2]: https://github.com/foreverjs/forever/blob/master/lib/forever/cli.js 261 | -------------------------------------------------------------------------------- /bin/forever: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | require('../lib/forever').cli.start(); 4 | -------------------------------------------------------------------------------- /bin/monitor: -------------------------------------------------------------------------------- 1 | var fs = require('fs'), 2 | path = require('path'), 3 | forever = require(path.resolve(__dirname, '..', 'lib', 'forever')), 4 | started; 5 | 6 | // 7 | // ### @function (file, pid) 8 | // #### @file {string} Location of the pid file. 9 | // #### @pid {number} pid to write to disk. 10 | // Write the pidFile to disk for later use 11 | // 12 | function writePid(file, pid) { 13 | fs.writeFileSync(file, String(pid), 'utf8'); 14 | } 15 | 16 | // 17 | // ### @function start (options) 18 | // #### @options {Object} Options for the `forever.Monitor` instance. 19 | // Starts the child process and disconnects from the IPC channel. 20 | // 21 | function start(options) { 22 | var script = process.argv[2], 23 | monitor = new forever.Monitor(script, options); 24 | 25 | forever.logEvents(monitor); 26 | monitor.start(); 27 | 28 | monitor.on('start', function () { 29 | // 30 | // This starts an nssocket server, which the forever CLI uses to 31 | // communicate with this monitor process after it's detached. 32 | // Without this, `forever list` won't show the process, even though it 33 | // would still be running in the background unaffected. 34 | // 35 | forever.startServer(monitor); 36 | 37 | // 38 | // Disconnect the IPC channel, letting this monitor's parent process know 39 | // that the child has started successfully. 40 | // 41 | process.disconnect(); 42 | 43 | // 44 | // Write the pidFile to disk 45 | // 46 | writePid(options.pidFile, monitor.child.pid); 47 | }); 48 | 49 | // 50 | // When the monitor restarts update the pid in the pidFile 51 | // 52 | monitor.on('restart', function () { 53 | writePid(options.pidFile, monitor.child.pid); 54 | }); 55 | 56 | 57 | // 58 | // When the monitor stops or exits, remove the pid and log files 59 | // 60 | function cleanUp() { 61 | try { 62 | fs.unlinkSync(options.pidFile); 63 | } 64 | catch(e) {} 65 | } 66 | monitor.on('stop', cleanUp); 67 | monitor.on('exit', cleanUp); 68 | } 69 | 70 | // 71 | // When we receive the first message from the parent process, start 72 | // an instance of `forever.Monitor` with the options supplied. 73 | // 74 | process.on('message', function (data) { 75 | // 76 | // TODO: Find out if this data will ever get split into two message events. 77 | // 78 | var options = JSON.parse(data.toString()); 79 | 80 | // inherits configuration from parent process if exists. 81 | options && options._loadedOptions && (forever.load(options._loadedOptions), delete options._loadedOptions); 82 | 83 | if (!started) { 84 | started = true; 85 | start(options); 86 | } 87 | }); 88 | -------------------------------------------------------------------------------- /lib/forever.js: -------------------------------------------------------------------------------- 1 | /* 2 | * forever.js: Top level include for the forever module 3 | * 4 | * (C) 2010 Charlie Robbins & the Contributors 5 | * MIT LICENCE 6 | * 7 | */ 8 | 9 | const fs = require("fs"); 10 | const path = require("path"); 11 | const events2 = require('eventemitter2'); 12 | const events = require("events"); 13 | const exec = require("child_process").exec; 14 | const spawn = require("child_process").spawn; 15 | const cliff = require("cliff"); 16 | const Configstore = require('configstore'); 17 | const nssocket = require("nssocket"); 18 | const utils = require("./util/utils"); 19 | const winston = require("winston"); 20 | const mkdirp = require("mkdirp"); 21 | const async = require("async"); 22 | const configUtils = require("./util/config-utils"); 23 | 24 | const forever = exports; 25 | 26 | const nodeVersion = process.versions.node 27 | function getNodeVersion() { 28 | const versionNumbers = nodeVersion.split('.') 29 | return { 30 | majorVersion: Number.parseInt(versionNumbers[0]), 31 | minorVersion: Number.parseInt(versionNumbers[1]), 32 | patchVersion: Number.parseInt(versionNumbers[2]), 33 | } 34 | } 35 | 36 | const versionNumbers = getNodeVersion(); 37 | function newEmitter() { 38 | if (versionNumbers.majorVersion > 6) { 39 | return new events.EventEmitter() 40 | } 41 | return new events2.EventEmitter2() 42 | } 43 | 44 | // 45 | // ### Export Components / Settings 46 | // Export `version` and important Prototypes from `lib/forever/*` 47 | // 48 | forever.initialized = false; 49 | forever.kill = require('forever-monitor').kill; 50 | forever.checkProcess = require('forever-monitor').checkProcess; 51 | forever.root = process.env.FOREVER_ROOT || path.join(process.env.HOME || process.env.USERPROFILE || '/root', '.forever'); 52 | forever.config = configUtils.initConfigFile(forever.root); 53 | forever.Forever = forever.Monitor = require('forever-monitor').Monitor; 54 | forever.Worker = require('./forever/worker').Worker; 55 | forever.cli = require('./forever/cli'); 56 | 57 | // 58 | // Expose version through `pkginfo` 59 | // 60 | exports.version = require('../package').version; 61 | 62 | // 63 | // Setup `forever.log` to be a custom `winston` logger. 64 | // 65 | forever.log = winston.createLogger({ 66 | transports: [ 67 | new (winston.transports.Console)() 68 | ], 69 | levels: winston.config.cli.levels, 70 | format: winston.format.cli(), 71 | }); 72 | 73 | // 74 | // Setup `forever out` for logEvents with `winston` custom logger. 75 | // 76 | forever.out = winston.createLogger({ 77 | format: (forever.config.get('timestamp') === 'true') ? winston.format.timestamp(): undefined, 78 | transports: [ 79 | new winston.transports.Console(), 80 | ], 81 | }); 82 | 83 | // 84 | // ### function getSockets (sockPath, callback) 85 | // #### @sockPath {string} Path in which to look for UNIX domain sockets 86 | // #### @callback {function} Continuation to pass control to when complete 87 | // Attempts to read the files from `sockPath` if the directory does not exist, 88 | // then it is created using `mkdirp`. 89 | // 90 | function getSockets(sockPath, callback) { 91 | let sockets; 92 | 93 | try { 94 | sockets = fs.readdirSync(sockPath); 95 | } 96 | catch (ex) { 97 | if (ex.code !== 'ENOENT') { 98 | return callback(ex); 99 | } 100 | 101 | return mkdirp(sockPath, '0755', function (err) { 102 | return err ? callback(err) : callback(null, []); 103 | }); 104 | } 105 | 106 | callback(null, sockets); 107 | } 108 | 109 | // 110 | // ### function getAllProcess (callback) 111 | // #### @callback {function} Continuation to respond to when complete. 112 | // Returns all data for processes managed by forever. 113 | // 114 | function getAllProcesses(callback) { 115 | const sockPath = forever.config.get("sockPath"); 116 | 117 | function getProcess(name, next) { 118 | let fullPath = path.join(sockPath, name); 119 | const socket = new nssocket.NsSocket(); 120 | 121 | if (process.platform === 'win32') { 122 | // it needs the prefix 123 | fullPath = '\\\\.\\pipe\\' + fullPath; 124 | } 125 | 126 | socket.connect(fullPath, function (err) { 127 | if (err) { 128 | next(err); 129 | } 130 | 131 | socket.dataOnce(['data'], function (data) { 132 | data.socket = fullPath; 133 | next(null, data); 134 | socket.end(); 135 | }); 136 | 137 | socket.send(['data']); 138 | }); 139 | 140 | socket.on('error', function (err) { 141 | if (err.code === 'ECONNREFUSED') { 142 | fs.unlink(fullPath, function () { 143 | next(); 144 | }); 145 | } 146 | else { 147 | next(); 148 | } 149 | }); 150 | } 151 | 152 | getSockets(sockPath, function (err, sockets) { 153 | if (err || (sockets && sockets.length === 0)) { 154 | return callback(err); 155 | } 156 | 157 | async.map(sockets, getProcess, function (err, processes) { 158 | callback(err, processes.filter(Boolean)); 159 | }); 160 | }); 161 | } 162 | 163 | // 164 | // ### function getAllPids () 165 | // Returns the set of all pids managed by forever. 166 | // e.x. [{ pid: 12345, foreverPid: 12346 }, ...] 167 | // 168 | function getAllPids(processes) { 169 | return !processes ? null : processes.map(function (proc) { 170 | return { 171 | pid: proc.pid, 172 | foreverPid: proc.foreverPid 173 | }; 174 | }); 175 | } 176 | 177 | // 178 | // ### function stopOrRestart (action, event, format, target) 179 | // #### @action {string} Action that is to be sent to target(s). 180 | // #### @event {string} Event that will be emitted on success. 181 | // #### @format {boolean} Indicated if we should CLI format the returned output. 182 | // #### @target {string} Index or script name to stop. Optional. 183 | // #### If not provided -> action will be sent to all targets. 184 | // Returns emitter that you can use to handle events on failure or success (i.e 'error' or ) 185 | // 186 | function stopOrRestart(action, event, format, target) { 187 | const emitter = newEmitter(); 188 | 189 | function sendAction(proc, next) { 190 | const socket = new nssocket.NsSocket(); 191 | 192 | function onMessage(data) { 193 | // 194 | // Cleanup the socket. 195 | // 196 | socket.undata([action, 'ok'], onMessage); 197 | socket.undata([action, 'error'], onMessage); 198 | socket.end(); 199 | 200 | // 201 | // Messages are only sent back from error cases. The event 202 | // calling context is available from `nssocket`. 203 | // 204 | const message = data && data.message 205 | const type = this.event.slice().pop(); 206 | 207 | // 208 | // Remark (Tjatse): This message comes from `forever-monitor`, the process is marked 209 | // as `STOPPED`: message: Cannot stop process that is not running. 210 | // 211 | // Remark (indexzero): We should probably warn instead of emitting an error in `forever-monitor`, 212 | // OR handle that error in `bin/worker` for better RPC. 213 | // 214 | return type === 'error' && /is not running/.test(message) 215 | ? next(new Error(message)) 216 | : next(null, data); 217 | } 218 | 219 | socket.connect(proc.socket, function (err) { 220 | if (err) { 221 | next(err); 222 | } 223 | 224 | socket.dataOnce([action, 'ok'], onMessage); 225 | socket.dataOnce([action, 'error'], onMessage); 226 | socket.send([action]); 227 | }); 228 | 229 | // 230 | // Remark (indexzero): This is a race condition, but unlikely to ever hit since 231 | // if the socket errors we will never get any data in the first place... 232 | // 233 | socket.on('error', function (err) { 234 | next(err); 235 | }); 236 | } 237 | 238 | 239 | getAllProcesses(function (err, processes) { 240 | if (err) { 241 | return process.nextTick(function () { 242 | emitter.emit('error', err); 243 | }); 244 | } 245 | 246 | let procs; 247 | if (target !== undefined && target !== null) { 248 | if (isNaN(target)) { 249 | procs = forever.findByScript(target, processes); 250 | } 251 | procs = procs 252 | || forever.findById(target, processes) 253 | || forever.findByIndex(target, processes) 254 | || forever.findByUid(target, processes) 255 | || forever.findByPid(target, processes); 256 | } 257 | else { 258 | procs = processes; 259 | } 260 | 261 | if (procs && procs.length > 0) { 262 | async.map(procs, sendAction, function (err, results) { 263 | if (err) { 264 | emitter.emit('error', err); 265 | } 266 | 267 | // 268 | // Remark (indexzero): we should do something with the results. 269 | // 270 | emitter.emit(event, forever.format(format, procs)); 271 | }); 272 | } 273 | else { 274 | process.nextTick(function () { 275 | emitter.emit('error', new Error('Cannot find forever process: ' + target)); 276 | }); 277 | } 278 | }); 279 | 280 | return emitter; 281 | } 282 | 283 | // 284 | // ### function load (options, [callback]) 285 | // #### @options {Object} Options to load into the forever module 286 | // Initializes configuration for forever module 287 | // 288 | forever.load = function (options) { 289 | // memorize current options. 290 | this._loadedOptions = options; 291 | 292 | // 293 | // Setup the incoming options with default options. 294 | // 295 | options = options || {}; 296 | options.loglength = options.loglength || 100; 297 | options.logstream = options.logstream || false; 298 | options.root = options.root || forever.root; 299 | options.pidPath = options.pidPath || path.join(options.root, 'pids'); 300 | options.sockPath = options.sockPath || path.join(options.root, 'sock'); 301 | 302 | // 303 | // If forever is initalized and the config directories are identical 304 | // simply return without creating directories 305 | // 306 | if (forever.initialized && forever.config.get('root') === options.root && 307 | forever.config.get('pidPath') === options.pidPath) { 308 | return; 309 | } 310 | 311 | // 312 | // Try to load the forever `config.json` from 313 | // the specified location. 314 | // 315 | forever.config = configUtils.initConfigFile(options.root); 316 | 317 | // 318 | // Setup the columns for `forever list`. 319 | // 320 | options.columns = options.columns || forever.config.get('columns'); 321 | if (!options.columns) { 322 | options.columns = [ 323 | 'uid', 'command', 'script', 'forever', 'pid', 'id', 'logfile', 'uptime' 324 | ]; 325 | } 326 | 327 | forever.config.set('root', options.root); 328 | forever.config.set('pidPath', options.pidPath); 329 | forever.config.set('sockPath', options.sockPath); 330 | forever.config.set('loglength', options.loglength); 331 | forever.config.set('logstream', options.logstream); 332 | forever.config.set('columns', options.columns); 333 | 334 | // 335 | // Attempt to see if `forever` has been configured to 336 | // run in debug mode. 337 | // 338 | options.debug = options.debug || forever.config.get('debug') || false; 339 | 340 | if (options.debug) { 341 | // 342 | // If we have been indicated to debug this forever process 343 | // then setup `forever._debug` to be an instance of `winston.Logger`. 344 | // 345 | forever._debug(); 346 | } 347 | 348 | configUtils.tryCreateDir(forever.config.get('root')); 349 | configUtils.tryCreateDir(forever.config.get('pidPath')); 350 | configUtils.tryCreateDir(forever.config.get('sockPath')); 351 | 352 | forever.initialized = true; 353 | }; 354 | 355 | // 356 | // ### @private function _debug () 357 | // Sets up debugging for this forever process 358 | // 359 | forever._debug = function () { 360 | const debug = forever.config.get("debug"); 361 | 362 | if (!debug) { 363 | forever.config.set('debug', true); 364 | forever.log.add(new winston.transports.File({ 365 | level: 'silly', 366 | filename: path.join(forever.config.get('root'), 'forever.debug.log'), 367 | })); 368 | } 369 | }; 370 | 371 | // 372 | // Ensure forever will always be loaded the first time it is required. 373 | // 374 | forever.load(); 375 | 376 | // 377 | // ### function stat (logFile, script, callback) 378 | // #### @logFile {string} Path to the log file for this script 379 | // #### @logAppend {boolean} Optional. True Prevent failure if the log file exists. 380 | // #### @script {string} Path to the target script. 381 | // #### @callback {function} Continuation to pass control back to 382 | // Ensures that the logFile doesn't exist and that 383 | // the target script does exist before executing callback. 384 | // 385 | forever.stat = function (logFile, script, callback) { 386 | let logAppend; 387 | 388 | if (arguments.length === 4) { 389 | logAppend = callback; 390 | callback = arguments[3]; 391 | } 392 | 393 | fs.stat(script, function (err, stats) { 394 | if (err) { 395 | return callback(new Error('script ' + script + ' does not exist.')); 396 | } 397 | 398 | return logAppend ? callback(null) : fs.stat(logFile, function (err, stats) { 399 | return !err 400 | ? callback(new Error('log file ' + logFile + ' exists. Use the -a or --append option to append log.')) 401 | : callback(null); 402 | }); 403 | }); 404 | }; 405 | 406 | // 407 | // ### function start (script, options) 408 | // #### @script {string} Location of the script to run. 409 | // #### @options {Object} Configuration for forever instance. 410 | // Starts a script with forever 411 | // 412 | forever.start = function (script, options) { 413 | if (!options.uid) { 414 | options.uid = utils.randomString(4).replace(/^\-/, '_'); 415 | } 416 | 417 | if (!options.logFile) { 418 | options.logFile = forever.logFilePath(options.uid + '.log'); 419 | } 420 | 421 | // 422 | // Create the monitor, log events, and start. 423 | // 424 | const monitor = new forever.Monitor(script, options); 425 | forever.logEvents(monitor); 426 | return monitor.start(); 427 | }; 428 | 429 | // 430 | // ### function startDaemon (script, options) 431 | // #### @script {string} Location of the script to run. 432 | // #### @options {Object} Configuration for forever instance. 433 | // Starts a script with forever as a daemon 434 | // 435 | forever.startDaemon = function (script, options) { 436 | options = options || {}; 437 | options.uid = options.uid || utils.randomString(4).replace(/^\-/, '_'); 438 | options.logFile = forever.logFilePath(options.logFile || forever.config.get('logFile') || options.uid + '.log'); 439 | options.pidFile = forever.pidFilePath(options.pidFile || forever.config.get('pidFile') || options.uid + '.pid'); 440 | 441 | // 442 | // This log file is forever's log file - the user's outFile and errFile 443 | // options are not taken into account here. This will be an aggregate of all 444 | // the app's output, as well as messages from the monitor process, where 445 | // applicable. 446 | // 447 | const outFD = fs.openSync(options.logFile, 'a'); 448 | const errFD = fs.openSync(options.logFile, 'a'); 449 | const monitorPath = path.resolve(__dirname, '..', 'bin', 'monitor'); 450 | 451 | const monitor = spawn(process.execPath, [monitorPath, script], { 452 | stdio: ['ipc', outFD, errFD], 453 | detached: true 454 | }); 455 | 456 | monitor.on('exit', function (code) { 457 | console.error('Monitor died unexpectedly with exit code %d', code); 458 | }); 459 | 460 | // transmit options to daemonic(child) process, keep configuration lineage. 461 | options._loadedOptions = this._loadedOptions; 462 | 463 | monitor.send(JSON.stringify(options)); 464 | 465 | // close the ipc communication channel with the monitor 466 | // otherwise the corresponding events listeners will prevent 467 | // the exit of the current process (observed with node 0.11.9) 468 | monitor.disconnect(); 469 | 470 | // make sure the monitor is unref() and does not prevent the 471 | // exit of the current process 472 | monitor.unref(); 473 | 474 | return monitor; 475 | }; 476 | 477 | // 478 | // ### function startServer () 479 | // #### @arguments {forever.Monitor...} A list of forever.Monitor instances 480 | // Starts the `forever` HTTP server for communication with the forever CLI. 481 | // **NOTE:** This will change your `process.title`. 482 | // 483 | forever.startServer = function () { 484 | const args = Array.prototype.slice.call(arguments); 485 | let monitors = [], 486 | callback; 487 | 488 | args.forEach(function (a) { 489 | if (Array.isArray(a)) { 490 | monitors = monitors.concat(a.filter(function (m) { 491 | return m instanceof forever.Monitor; 492 | })); 493 | } 494 | else if (a instanceof forever.Monitor) { 495 | monitors.push(a); 496 | } 497 | else if (typeof a === 'function') { 498 | callback = a; 499 | } 500 | }); 501 | 502 | async.map(monitors, function (monitor, next) { 503 | const worker = new forever.Worker({ 504 | monitor: monitor, 505 | sockPath: forever.config.get("sockPath"), 506 | exitOnStop: true 507 | }); 508 | 509 | worker.start(function (err) { 510 | return err ? next(err) : next(null, worker); 511 | }); 512 | }, callback || function () {}); 513 | }; 514 | 515 | 516 | // 517 | // ### function stop (target, [format]) 518 | // #### @target {string} Index or script name to stop 519 | // #### @format {boolean} Indicated if we should CLI format the returned output. 520 | // Stops the process(es) with the specified index or script name 521 | // in the list of all processes 522 | // 523 | forever.stop = function (target, format) { 524 | return stopOrRestart('stop', 'stop', format, target); 525 | }; 526 | 527 | // 528 | // ### function restart (target, format) 529 | // #### @target {string} Index or script name to restart 530 | // #### @format {boolean} Indicated if we should CLI format the returned output. 531 | // Restarts the process(es) with the specified index or script name 532 | // in the list of all processes 533 | // 534 | forever.restart = function (target, format) { 535 | return stopOrRestart('restart', 'restart', format, target); 536 | }; 537 | 538 | // 539 | // ### function stopbypid (target, format) 540 | // #### @pid {string} Pid of process to stop. 541 | // #### @format {boolean} Indicated if we should CLI format the returned output. 542 | // Stops the process with specified pid 543 | // 544 | forever.stopbypid = function (pid, format) { 545 | // stopByPid only capable of stopping, but can't restart 546 | return stopOrRestart('stop', 'stopByPid', format, pid); 547 | }; 548 | 549 | // 550 | // ### function restartAll (format) 551 | // #### @format {boolean} Value indicating if we should format output 552 | // Restarts all processes managed by forever. 553 | // 554 | forever.restartAll = function (format) { 555 | return stopOrRestart('restart', 'restartAll', format); 556 | }; 557 | 558 | // 559 | // ### function stopAll (format) 560 | // #### @format {boolean} Value indicating if we should format output 561 | // Stops all processes managed by forever. 562 | // 563 | forever.stopAll = function (format) { 564 | return stopOrRestart('stop', 'stopAll', format); 565 | }; 566 | 567 | // 568 | // ### function list (format, procs, callback) 569 | // #### @format {boolean} If set, will return a formatted string of data 570 | // #### @callback {function} Continuation to respond to when complete. 571 | // Returns the list of all process data managed by forever. 572 | // 573 | forever.list = function (format, callback) { 574 | getAllProcesses(function (err, processes) { 575 | callback(err, forever.format(format, processes)); 576 | }); 577 | }; 578 | 579 | // 580 | // ### function tail (target, length, callback) 581 | // #### @target {string} Target script to list logs for 582 | // #### @options {length|stream} **Optional** Length of the logs to tail, boolean stream 583 | // #### @callback {function} Continuation to respond to when complete. 584 | // Responds with the latest `length` logs for the specified `target` process 585 | // managed by forever. If no `length` is supplied then `forever.config.get('loglength`)` 586 | // is used. 587 | // 588 | forever.tail = function (target, options, callback) { 589 | if (!callback && typeof options === 'function') { 590 | callback = options; 591 | options.length = 0; 592 | options.stream = false; 593 | } 594 | 595 | const that = this, 596 | length = options.length || forever.config.get("loglength"), 597 | stream = options.stream || forever.config.get("logstream"), 598 | blanks = function(e, i, a) { 599 | return e !== ""; 600 | }, 601 | title = function(e, i, a) { 602 | return e.match(/^==>/); 603 | }, 604 | args = ["-n", length]; 605 | let logs; 606 | 607 | if (stream) { args.unshift('-f'); } 608 | 609 | function tailProcess(procs, next) { 610 | let count = 0; 611 | const map = {}; 612 | 613 | procs.forEach(function (proc) { 614 | args.push(proc.logFile); 615 | map[proc.logFile] = { pid: proc.pid, file: proc.file }; 616 | count++; 617 | }); 618 | 619 | const tail = spawn('tail', args, { 620 | stdio: [null, 'pipe', 'pipe'], 621 | }); 622 | 623 | tail.stdio[1].setEncoding('utf8'); 624 | tail.stdio[2].setEncoding('utf8'); 625 | 626 | tail.stdio[1].on('data', function (data) { 627 | const chunk = data.split("\n\n"); 628 | chunk.forEach(function (logs) { 629 | const filteredLogs = logs.split("\n").filter(blanks), 630 | file = filteredLogs.filter(title); 631 | 632 | const proc = file.length 633 | ? map[file[0].split(' ')[1]] 634 | : map[procs[0].logFile]; 635 | 636 | const lines = count !== 1 637 | ? filteredLogs.slice(1) 638 | : filteredLogs; 639 | 640 | lines.forEach(function (line) { 641 | callback(null, { file: proc.file, pid: proc.pid, line: line }); 642 | }); 643 | }); 644 | }); 645 | 646 | tail.stdio[2].on('data', function (err) { 647 | return callback(err); 648 | }); 649 | } 650 | 651 | getAllProcesses(function (err, processes) { 652 | if (err) { 653 | return callback(err); 654 | } 655 | else if (!processes) { 656 | return callback(new Error('Cannot find forever process: ' + target)); 657 | } 658 | 659 | const procs = forever.findByIndex(target, processes) 660 | || forever.findByScript(target, processes); 661 | 662 | if (!procs) { 663 | return callback(new Error('No logs available for process: ' + target)); 664 | } 665 | 666 | tailProcess(procs, callback); 667 | }); 668 | }; 669 | 670 | // 671 | // ### function findById (id, processes) 672 | // #### @id {string} id of the process to find. 673 | // #### @processes {Array} Set of processes to find in. 674 | // Finds the process with the specified index. 675 | // 676 | forever.findById = function (id, processes) { 677 | if (!processes) { return null; } 678 | 679 | let procs = processes.filter(function(p) { 680 | return p.id === id; 681 | }); 682 | 683 | if (procs.length === 0) { procs = null; } 684 | return procs; 685 | }; 686 | 687 | // 688 | // ### function findByIndex (index, processes) 689 | // #### @index {string} Index of the process to find. 690 | // #### @processes {Array} Set of processes to find in. 691 | // Finds the process with the specified index. 692 | // 693 | forever.findByIndex = function (index, processes) { 694 | const indexAsNum = parseInt(index, 10); 695 | let proc; 696 | 697 | if (indexAsNum == index) { 698 | proc = processes && processes[indexAsNum]; 699 | } 700 | return proc ? [proc] : null; 701 | }; 702 | 703 | // 704 | // ### function findByScript (script, processes) 705 | // #### @script {string} The name of the script to find. 706 | // #### @processes {Array} Set of processes to find in. 707 | // Finds the process with the specified script name. 708 | // 709 | forever.findByScript = function (script, processes) { 710 | if (!processes) { return null; } 711 | 712 | // make script absolute. 713 | if (script.indexOf('/') != 0) { 714 | script = path.resolve(process.cwd(), script); 715 | } 716 | 717 | let procs = processes.filter(function(p) { 718 | return p.file === script || path.join(p.spawnWith.cwd, p.file) === script; 719 | }); 720 | 721 | if (procs.length === 0) { procs = null; } 722 | return procs; 723 | }; 724 | 725 | // 726 | // ### function findByUid (uid, processes) 727 | // #### @uid {string} The uid of the process to find. 728 | // #### @processes {Array} Set of processes to find in. 729 | // Finds the process with the specified uid. 730 | // 731 | forever.findByUid = function (script, processes) { 732 | let procs = !processes 733 | ? null 734 | : processes.filter(function(p) { 735 | return p.uid === script; 736 | }); 737 | 738 | if (procs && procs.length === 0) { procs = null; } 739 | return procs; 740 | }; 741 | 742 | // 743 | // ### function findByPid (pid, processes) 744 | // #### @pid {string} The pid of the process to find. 745 | // #### @processes {Array} Set of processes to find in. 746 | // Finds the process with the specified pid. 747 | // 748 | forever.findByPid = function (pid, processes) { 749 | pid = typeof pid === 'string' 750 | ? parseInt(pid, 10) 751 | : pid; 752 | 753 | let procs = processes && processes.filter(function(p) { 754 | return p.pid === pid; 755 | }); 756 | 757 | if (procs && procs.length === 0) { procs = null; } 758 | return procs || null; 759 | }; 760 | 761 | // 762 | // ### function format (format, procs) 763 | // #### @format {Boolean} Value indicating if processes should be formatted 764 | // #### @procs {Array} Processes to format 765 | // Returns a formatted version of the `procs` supplied based on the column 766 | // configuration in `forever.config`. 767 | // 768 | forever.format = function (format, procs) { 769 | if (!procs || procs.length === 0) { 770 | return null; 771 | } 772 | 773 | let index = 0; 774 | const columns = forever.config.get("columns"), 775 | rows = [[" "].concat(columns)]; 776 | let formatted; 777 | 778 | function mapColumns(prefix, mapFn) { 779 | return [prefix].concat(columns.map(mapFn)); 780 | } 781 | 782 | if (format) { 783 | // 784 | // Iterate over the procs to see which has the 785 | // longest options string 786 | // 787 | procs.forEach(function (proc) { 788 | rows.push(mapColumns('[' + index + ']', function (column) { 789 | return forever.columns[column] 790 | ? forever.columns[column].get(proc) 791 | : 'MISSING'; 792 | })); 793 | 794 | index++; 795 | }); 796 | 797 | formatted = cliff.stringifyRows(rows, mapColumns('white', function (column) { 798 | return forever.columns[column] 799 | ? forever.columns[column].color 800 | : 'white'; 801 | })); 802 | } 803 | 804 | return format ? formatted : procs; 805 | }; 806 | 807 | // 808 | // ### function cleanUp () 809 | // Utility function for removing excess pid and 810 | // config, and log files used by forever. 811 | // 812 | forever.cleanUp = function (cleanLogs, allowManager) { 813 | const emitter = newEmitter(), 814 | pidPath = forever.config.get("pidPath"); 815 | 816 | getAllProcesses(function (err, processes) { 817 | if (err) { 818 | return process.nextTick(function () { 819 | emitter.emit('error', err); 820 | }); 821 | } 822 | else if (cleanLogs) { 823 | forever.cleanLogsSync(processes); 824 | } 825 | 826 | function unlinkProcess(proc, done) { 827 | fs.unlink(path.join(pidPath, proc.uid + '.pid'), function () { 828 | // 829 | // Ignore errors (in case the file doesnt exist). 830 | // 831 | 832 | if (cleanLogs && proc.logFile) { 833 | // 834 | // If we are cleaning logs then do so if the process 835 | // has a logfile. 836 | // 837 | return fs.unlink(proc.logFile, function () { 838 | done(); 839 | }); 840 | } 841 | 842 | done(); 843 | }); 844 | } 845 | 846 | function cleanProcess(proc, done) { 847 | if (proc.child && proc.manager) { 848 | return done(); 849 | } 850 | else if (!proc.child && !proc.manager 851 | || (!proc.child && proc.manager && allowManager) 852 | || proc.dead) { 853 | return unlinkProcess(proc, done); 854 | } 855 | 856 | // 857 | // If we have a manager but no child, wait a moment 858 | // in-case the child is currently restarting, but **only** 859 | // if we have not already waited for this process 860 | // 861 | if (!proc.waited) { 862 | proc.waited = true; 863 | return setTimeout(function () { 864 | checkProcess(proc, done); 865 | }, 500); 866 | } 867 | 868 | done(); 869 | } 870 | 871 | function checkProcess(proc, next) { 872 | proc.child = forever.checkProcess(proc.pid); 873 | proc.manager = forever.checkProcess(proc.foreverPid); 874 | cleanProcess(proc, next); 875 | } 876 | 877 | if (processes && processes.length > 0) { 878 | (function cleanBatch(batch) { 879 | async.forEach(batch, checkProcess, function () { 880 | return processes.length > 0 881 | ? cleanBatch(processes.splice(0, 10)) 882 | : emitter.emit('cleanUp'); 883 | }); 884 | })(processes.splice(0, 10)); 885 | } 886 | else { 887 | process.nextTick(function () { 888 | emitter.emit('cleanUp'); 889 | }); 890 | } 891 | }); 892 | 893 | return emitter; 894 | }; 895 | 896 | // 897 | // ### function cleanLogsSync (processes) 898 | // #### @processes {Array} The set of all forever processes 899 | // Removes all log files from the root forever directory 900 | // that do not belong to current running forever processes. 901 | // 902 | forever.cleanLogsSync = function (processes) { 903 | const root = forever.config.get("root"), 904 | files = fs.readdirSync(root); 905 | 906 | const running = processes && processes.filter(function (p) { 907 | return p && p.logFile; 908 | }); 909 | 910 | const runningLogs = running && running.map(function (p) { 911 | return p.logFile.split('/').pop(); 912 | }); 913 | 914 | files.forEach(function (file) { 915 | if (/\.log$/.test(file) && (!runningLogs || runningLogs.indexOf(file) === -1)) { 916 | fs.unlinkSync(path.join(root, file)); 917 | } 918 | }); 919 | }; 920 | 921 | // 922 | // ### function logFilePath (logFile) 923 | // #### @logFile {string} Log file path 924 | // Determines the full logfile path name 925 | // 926 | forever.logFilePath = function (logFile, uid) { 927 | return logFile && (logFile[0] === '/' || logFile[1] === ':') 928 | ? logFile 929 | : path.join(forever.config.get('root'), logFile || (uid || 'forever') + '.log'); 930 | }; 931 | 932 | // 933 | // ### function pidFilePath (pidFile) 934 | // #### @logFile {string} Pid file path 935 | // Determines the full pid file path name 936 | // 937 | forever.pidFilePath = function (pidFile) { 938 | return pidFile && (pidFile[0] === '/' || pidFile[1] === ':') 939 | ? pidFile 940 | : path.join(forever.config.get('pidPath'), pidFile); 941 | }; 942 | 943 | // 944 | // ### @function logEvents (monitor) 945 | // #### @monitor {forever.Monitor} Monitor to log events for 946 | // Logs important restart and error events to `console.error` 947 | // 948 | forever.logEvents = function (monitor) { 949 | monitor.on('watch:error', function (info) { 950 | forever.out.error(info.message); 951 | forever.out.error(info.error); 952 | }); 953 | 954 | monitor.on('watch:restart', function (info) { 955 | forever.out.error('restarting script because ' + info.file + ' changed'); 956 | }); 957 | 958 | monitor.on('restart', function () { 959 | forever.out.error('Script restart attempt #' + monitor.times); 960 | }); 961 | 962 | monitor.on('exit:code', function (code, signal) { 963 | forever.out.error((code !== null && code !== undefined) 964 | ? 'Forever detected script exited with code: ' + code 965 | : 'Forever detected script was killed by signal: ' + signal); 966 | }); 967 | }; 968 | 969 | // 970 | // ### @columns {Object} 971 | // Property descriptors for accessing forever column information 972 | // through `forever list` and `forever.list()` 973 | // 974 | forever.columns = { 975 | uid: { 976 | color: 'white', 977 | get: function (proc) { 978 | return proc.uid; 979 | } 980 | }, 981 | id: { 982 | color: 'white', 983 | get: function (proc) { 984 | return proc.id ? proc.id : ''; 985 | } 986 | }, 987 | command: { 988 | color: 'grey', 989 | get: function (proc) { 990 | return (proc.command || 'node').grey; 991 | } 992 | }, 993 | script: { 994 | color: 'grey', 995 | get: function (proc) { 996 | return [proc.file].concat(proc.args).join(' ').grey; 997 | } 998 | }, 999 | forever: { 1000 | color: 'white', 1001 | get: function (proc) { 1002 | return proc.foreverPid; 1003 | } 1004 | }, 1005 | pid: { 1006 | color: 'white', 1007 | get: function (proc) { 1008 | return proc.pid; 1009 | } 1010 | }, 1011 | logfile: { 1012 | color: 'magenta', 1013 | get: function (proc) { 1014 | return proc.logFile ? proc.logFile.magenta : ''; 1015 | } 1016 | }, 1017 | dir: { 1018 | color: 'grey', 1019 | get: function (proc) { 1020 | return proc.sourceDir.grey; 1021 | } 1022 | }, 1023 | uptime: { 1024 | color: 'yellow', 1025 | get: function (proc) { 1026 | if (!proc.running) { 1027 | return "STOPPED".red; 1028 | } 1029 | 1030 | let delta = (new Date().getTime() - proc.ctime) / 1000; 1031 | const days = Math.floor(delta / 86400); 1032 | delta -= days * 86400; 1033 | const hours = Math.floor(delta / 3600) % 24; 1034 | delta -= hours * 3600; 1035 | const minutes = Math.floor(delta / 60) % 60; 1036 | delta -= minutes * 60; 1037 | const seconds = delta % 60; 1038 | 1039 | return (days+':'+hours+':'+minutes+':'+seconds).yellow; 1040 | } 1041 | } 1042 | }; 1043 | -------------------------------------------------------------------------------- /lib/forever/cli.js: -------------------------------------------------------------------------------- 1 | /* 2 | * cli.js: Handlers for the forever CLI commands. 3 | * 4 | * (C) 2010 Charlie Robbins & the Contributors 5 | * MIT LICENCE 6 | * 7 | */ 8 | 9 | var fs = require('fs'), 10 | path = require('path'), 11 | util = require('util'), 12 | colors = require('@colors/colors'), 13 | cliff = require('cliff'), 14 | flatiron = require('flatiron'), 15 | shush = require('shush'), 16 | prettyjson = require('prettyjson'), 17 | clone = require('clone'), 18 | objectAssign = require('object-assign'), 19 | forever = require('../forever'); 20 | 21 | var cli = exports; 22 | 23 | var help = [ 24 | 'usage: forever [action] [options] SCRIPT [script-options]', 25 | '', 26 | 'Monitors the script specified in the current process or as a daemon', 27 | '', 28 | 'actions:', 29 | ' start Start SCRIPT as a daemon', 30 | ' stop Stop the daemon SCRIPT by Id|Uid|Pid|Index|Script', 31 | ' stopall Stop all running forever scripts', 32 | ' restart Restart the daemon SCRIPT', 33 | ' restartall Restart all running forever scripts', 34 | ' list List all running forever scripts', 35 | ' config Lists all forever user configuration', 36 | ' set Sets the specified forever config ', 37 | ' clear Clears the specified forever config ', 38 | ' logs Lists log files for all forever processes', 39 | ' logs Tails the logs for ', 40 | ' columns add Adds the specified column to the output in `forever list`. Supported columns: \'uid\', \'command\', \'script\', \'forever\', \'pid\', \'id\', \'logfile\', \'uptime\'', 41 | ' columns rm Removed the specified column from the output in `forever list`', 42 | ' columns set Set all columns for the output in `forever list`', 43 | ' columns reset Resets all columns to defaults for the output in `forever list`', 44 | ' cleanlogs [CAREFUL] Deletes all historical forever log files', 45 | '', 46 | 'options:', 47 | ' -m MAX Only run the specified script MAX times', 48 | ' -l LOGFILE Logs the forever output to LOGFILE', 49 | ' -o OUTFILE Logs stdout from child script to OUTFILE', 50 | ' -e ERRFILE Logs stderr from child script to ERRFILE', 51 | ' -p PATH Base path for all forever related files (pid files, etc.)', 52 | ' -c COMMAND COMMAND to execute (defaults to node)', 53 | ' -a, --append Append logs', 54 | ' -f, --fifo Stream logs to stdout', 55 | ' -n, --number Number of log lines to print', 56 | ' --pidFile The pid file', 57 | ' --uid Process uid, useful as a namespace for processes (must wrap in a string)', 58 | ' e.g. forever start --uid "production" app.js', 59 | ' forever stop production', 60 | ' --sourceDir The source directory for which SCRIPT is relative to', 61 | ' --workingDir The working directory in which SCRIPT will execute', 62 | ' --minUptime Minimum uptime (millis) for a script to not be considered "spinning"', 63 | ' --spinSleepTime Time to wait (millis) between launches of a spinning script.', 64 | ' --colors --no-colors will disable output coloring', 65 | ' --plain alias of --no-colors', 66 | ' -d, --debug Forces forever to log debug output', 67 | ' -v, --verbose Turns on the verbose messages from Forever', 68 | ' -s, --silent Run the child script silencing stdout and stderr', 69 | ' -w, --watch Watch for file changes', 70 | ' --watchDirectory Top-level directory to watch from', 71 | ' --watchIgnore To ignore pattern when watch is enabled (multiple option is allowed)', 72 | ' -t, --killTree Kills the entire child process tree on `stop`', 73 | ' --killSignal Support exit signal customization (default is SIGKILL)', 74 | ' used for restarting script gracefully e.g. --killSignal=SIGTERM', 75 | ' --version Print the current version', 76 | ' -h, --help You\'re staring at it', 77 | '', 78 | '[Long Running Process]', 79 | ' The forever process will continue to run outputting log messages to the console.', 80 | ' ex. forever -o out.log -e err.log my-script.js', 81 | '', 82 | '[Daemon]', 83 | ' The forever process will run as a daemon which will make the target process start', 84 | ' in the background. This is extremely useful for remote starting simple node.js scripts', 85 | ' without using nohup. It is recommended to run start with -o -l, & -e.', 86 | ' ex. forever start -l forever.log -o out.log -e err.log my-daemon.js', 87 | ' forever stop my-daemon.js', 88 | '' 89 | ]; 90 | 91 | var app = flatiron.app; 92 | 93 | var actions = [ 94 | 'start', 95 | 'stop', 96 | 'stopbypid', 97 | 'stopall', 98 | 'restart', 99 | 'restartall', 100 | 'list', 101 | 'config', 102 | 'set', 103 | 'clear', 104 | 'logs', 105 | 'columns', 106 | 'cleanlogs' 107 | ]; 108 | 109 | var argvOptions = cli.argvOptions = { 110 | 'command': {alias: 'c'}, 111 | 'errFile': {alias: 'e'}, 112 | 'logFile': {alias: 'l'}, 113 | 'killTree': {alias: 't', boolean: true}, 114 | 'append': {alias: 'a', boolean: true}, 115 | 'fifo': {alias: 'f', boolean: true}, 116 | 'number': {alias: 'n'}, 117 | 'max': {alias: 'm'}, 118 | 'outFile': {alias: 'o'}, 119 | 'path': {alias: 'p'}, 120 | 'help': {alias: 'h'}, 121 | 'silent': {alias: 's', boolean: true}, 122 | 'verbose': {alias: 'v', boolean: true}, 123 | 'watch': {alias: 'w', boolean: true}, 124 | 'debug': {alias: 'd', boolean: true}, 125 | 'plain': {boolean: true}, 126 | 'uid': {alias: 'u'} 127 | }; 128 | 129 | app.use(flatiron.plugins.cli, { 130 | argv: argvOptions, 131 | usage: help 132 | }); 133 | 134 | var reserved = ['root', 'pidPath']; 135 | 136 | // 137 | // ### @private function (file, options, callback) 138 | // #### @file {string} Target script to start 139 | // #### @options {Object} Options to start the script with 140 | // #### @callback {function} Continuation to respond to when complete. 141 | // Helper function that sets up the pathing for the specified `file` 142 | // then stats the appropriate files and responds. 143 | // 144 | function tryStart(file, options, callback) { 145 | var fullLog, fullScript; 146 | 147 | if (options.path) { 148 | forever.config.set('root', options.path); 149 | forever.root = options.path; 150 | } 151 | 152 | fullLog = forever.logFilePath(options.logFile, options.uid); 153 | fullScript = path.join(options.sourceDir, file); 154 | 155 | forever.stat(fullLog, fullScript, options.append, function (err) { 156 | if (err) { 157 | forever.log.error('Cannot start forever'); 158 | forever.log.error(err.message); 159 | process.exit(-1); 160 | } 161 | 162 | callback(); 163 | }); 164 | } 165 | 166 | // 167 | // ### @private function updateConfig (updater) 168 | // #### @updater {function} Function which updates the forever config 169 | // Helper which runs the specified `updater` and then saves the forever 170 | // config to `forever.config.get('root')`. 171 | // 172 | function updateConfig(updater) { 173 | updater(); 174 | forever.config.save(function (err) { 175 | if (err) { 176 | return forever.log.error('Error saving config: ' + err.message); 177 | } 178 | 179 | cli.config(); 180 | var configFile = path.join(forever.config.get('root'), 'config.json'); 181 | forever.log.info('Forever config saved: ' + configFile.yellow); 182 | }); 183 | } 184 | 185 | // 186 | // ### @private function checkColumn (name) 187 | // #### @name {string} Column to check 188 | // Checks if column `name` exists 189 | // 190 | function checkColumn(name) { 191 | if (!forever.columns[name]) { 192 | forever.log.error('Unknown column: ' + name.magenta); 193 | return false; 194 | } 195 | return true; 196 | } 197 | 198 | // 199 | // ### function getOptions (file) 200 | // #### @file {string} File to run. **Optional** 201 | // Returns `options` object for use with `forever.start` and 202 | // `forever.startDaemon` 203 | // 204 | var getOptions = cli.getOptions = function (file) { 205 | var options = {}, 206 | absFile = path.isAbsolute(file) ? file : path.resolve(process.cwd(), file), 207 | configKeys = [ 208 | 'pidFile', 'logFile', 'errFile', 'watch', 'minUptime', 'append', 209 | 'silent', 'outFile', 'max', 'command', 'path', 'spinSleepTime', 210 | 'sourceDir', 'workingDir', 'uid', 'watchDirectory', 'watchIgnore', 211 | 'killTree', 'killSignal', 'id' 212 | ], 213 | specialKeys = ['script', 'args'], 214 | configs; 215 | 216 | // 217 | // Load JSON configuration values 218 | // 219 | if (path.extname(file) === '.json') { 220 | configs = shush(absFile); 221 | configs = !Array.isArray(configs) ? [configs] : configs; 222 | 223 | configs = configs.map(function (conf) { 224 | var mut = Object.keys(conf) 225 | .reduce(function (acc, key) { 226 | if (~configKeys.indexOf(key) || ~specialKeys.indexOf(key)) { 227 | acc[key] = conf[key]; 228 | } 229 | 230 | return acc; 231 | }, {}); 232 | 233 | if (!mut.script) { 234 | forever.log.error('"script" option required in JSON configuration files'); 235 | console.log(prettyjson.render(mut)); 236 | process.exit(1); 237 | } 238 | 239 | return mut; 240 | }); 241 | } else { 242 | options.script = file; 243 | } 244 | 245 | // 246 | // First isolate options which should be passed to file 247 | // 248 | options.args = process.argv.splice(process.argv.indexOf(file) + 1); 249 | 250 | // 251 | // Now we have to force reparsing of command line options because 252 | // we've removed some before. 253 | // 254 | app.config.stores.argv.store = {}; 255 | app.config.use('argv', argvOptions); 256 | 257 | configKeys.forEach(function (key) { 258 | options[key] = app.config.get(key); 259 | }); 260 | 261 | options.watchIgnore = options.watchIgnore || []; 262 | options.watchIgnorePatterns = Array.isArray(options.watchIgnore) 263 | ? options.watchIgnore 264 | : [options.watchIgnore]; 265 | 266 | if (!options.minUptime) { 267 | forever.log.warn('--minUptime not set. Defaulting to: 1000ms'); 268 | options.minUptime = 1000; 269 | } 270 | 271 | if (!options.spinSleepTime) { 272 | forever.log.warn([ 273 | '--spinSleepTime not set. Your script', 274 | 'will exit if it does not stay up for', 275 | 'at least ' + options.minUptime + 'ms' 276 | ].join(' ')); 277 | } 278 | 279 | function assignSpawnWith(options) { 280 | options.sourceDir = options.sourceDir || (file && file[0] !== '/' ? process.cwd() : '/'); 281 | options.workingDir = options.workingDir || options.sourceDir; 282 | options.spawnWith = { cwd: options.workingDir }; 283 | return options; 284 | } 285 | 286 | if (configs && configs.length) { 287 | return configs.map(function (conf) { 288 | return assignSpawnWith(objectAssign(clone(options), conf)); 289 | }); 290 | } 291 | 292 | return [assignSpawnWith(options)]; 293 | }; 294 | 295 | // 296 | // ### function cleanLogs 297 | // Deletes all historical forever log files 298 | // 299 | app.cmd('cleanlogs', cli.cleanLogs = function () { 300 | forever.log.silly('Tidying ' + forever.config.get('root')); 301 | forever.cleanUp(true).on('cleanUp', function () { 302 | forever.log.silly(forever.config.get('root') + ' tidied.'); 303 | }); 304 | }); 305 | 306 | // 307 | // ### function start (file) 308 | // #### @file {string} Location of the script to spawn with forever 309 | // Starts a forever process for the script located at `file` as daemon 310 | // process. 311 | // 312 | app.cmd(/start (.+)/, cli.startDaemon = function () { 313 | var file = app.argv._[1], 314 | options = getOptions(file); 315 | 316 | options.forEach(function (o) { 317 | forever.log.info('Forever processing file: ' + o.script.grey); 318 | tryStart(o.script, o, function () { 319 | forever.startDaemon(o.script, o); 320 | }); 321 | }); 322 | 323 | }); 324 | 325 | // 326 | // ### function stop (file) 327 | // #### @file {string} Target forever process to stop 328 | // Stops the forever process specified by `file`. 329 | // 330 | app.cmd(/stop (.+)/, cli.stop = function (file) { 331 | var runner = forever.stop(file, true); 332 | 333 | runner.on('stop', function (process) { 334 | forever.log.info('Forever stopped process:' + '\n' + process); 335 | }); 336 | 337 | runner.on('error', function (err) { 338 | forever.log.error('Forever cannot find process with id: ' + file); 339 | process.exit(1); 340 | }); 341 | }); 342 | 343 | // 344 | // ### function stopbypid (pid) 345 | // Stops running forever process by pid. 346 | // 347 | app.cmd(/stopbypid (.+)/, cli.stopbypid = function (pid) { 348 | forever.log.warn('Deprecated, try `forever stop ' + pid + '` instead.'); 349 | cli.stop(pid); 350 | }); 351 | 352 | // 353 | // ### function stopall () 354 | // Stops all currently running forever processes. 355 | // 356 | app.cmd('stopall', cli.stopall = function () { 357 | var runner = forever.stopAll(true); 358 | runner.on('stopAll', function (processes) { 359 | if (processes) { 360 | forever.log.info('Forever stopped processes:'); 361 | processes.split('\n').forEach(function (line) { 362 | forever.log.data(line); 363 | }); 364 | } 365 | else { 366 | forever.log.info('No forever processes running'); 367 | } 368 | }); 369 | 370 | runner.on('error', function () { 371 | forever.log.info('No forever processes running'); 372 | }); 373 | }); 374 | 375 | // 376 | // ### function restartall () 377 | // Restarts all currently running forever processes. 378 | // 379 | app.cmd('restartall', cli.restartAll = function () { 380 | var runner = forever.restartAll(true); 381 | runner.on('restartAll', function (processes) { 382 | if (processes) { 383 | forever.log.info('Forever restarted processes:'); 384 | processes.split('\n').forEach(function (line) { 385 | forever.log.data(line); 386 | }); 387 | } 388 | else { 389 | forever.log.info('No forever processes running'); 390 | } 391 | }); 392 | 393 | runner.on('error', function () { 394 | forever.log.info('No forever processes running'); 395 | }); 396 | }); 397 | 398 | // 399 | // ### function restart (file) 400 | // #### @file {string} Target process to restart 401 | // Restarts the forever process specified by `file`. 402 | // 403 | app.cmd(/restart (.+)/, cli.restart = function (file) { 404 | var runner = forever.restart(file, true); 405 | runner.on('restart', function (processes) { 406 | if (processes) { 407 | forever.log.info('Forever restarted process(es):'); 408 | processes.split('\n').forEach(function (line) { 409 | forever.log.data(line); 410 | }); 411 | } 412 | else { 413 | forever.log.info('No forever processes running'); 414 | } 415 | }); 416 | 417 | runner.on('error', function (err) { 418 | forever.log.error('Error restarting process: ' + file.grey); 419 | forever.log.error(err.message); 420 | process.exit(1); 421 | }); 422 | }); 423 | 424 | // 425 | // ### function list () 426 | // Lists all currently running forever processes. 427 | // 428 | app.cmd('list', cli.list = function () { 429 | forever.list(true, function (err, processes) { 430 | if (processes) { 431 | forever.log.info('Forever processes running'); 432 | processes.split('\n').forEach(function (line) { 433 | forever.log.data(line); 434 | }); 435 | } 436 | else { 437 | forever.log.info('No forever processes running'); 438 | } 439 | }); 440 | }); 441 | 442 | // 443 | // ### function config () 444 | // Lists all of the configuration in `~/.forever/config.json`. 445 | // 446 | app.cmd('config', cli.config = function () { 447 | var keys = Object.keys(forever.config.all), 448 | conf = cliff.inspect(forever.config.all); 449 | 450 | if (keys.length <= 2) { 451 | conf = conf.replace(/\{\s/, '{ \n') 452 | .replace(/\}/, '\n}') 453 | .replace('\\033[90m', ' \\033[90m') 454 | .replace(/, /ig, ',\n '); 455 | } 456 | else { 457 | conf = conf.replace(/\n\s{4}/ig, '\n '); 458 | } 459 | 460 | conf.split('\n').forEach(function (line) { 461 | forever.log.data(line); 462 | }); 463 | }); 464 | 465 | // 466 | // ### function set (key, value) 467 | // #### @key {string} Key to set in forever config 468 | // #### @value {string} Value to set for `key` 469 | // Sets the specified `key` / `value` pair in the 470 | // forever user config. 471 | // 472 | app.cmd(/set ([\w-_]+) (.+)/, cli.set = function (key, value) { 473 | updateConfig(function () { 474 | forever.log.info('Setting forever config: ' + key.grey); 475 | forever.config.set(key, value); 476 | }); 477 | }); 478 | 479 | // 480 | // ### function clear (key) 481 | // #### @key {string} Key to remove from `~/.forever/config.json` 482 | // Removes the specified `key` from the forever user config. 483 | // 484 | app.cmd('clear :key', cli.clear = function (key) { 485 | if (reserved.indexOf(key) !== -1) { 486 | forever.log.warn('Cannot clear reserved config: ' + key.grey); 487 | forever.log.warn('Use `forever set ' + key + '` instead'); 488 | return; 489 | } 490 | 491 | updateConfig(function () { 492 | forever.log.info('Clearing forever config: ' + key.grey); 493 | forever.config.clear(key); 494 | }); 495 | }); 496 | 497 | // 498 | // ### function logs (target) 499 | // #### @target {string} Target script or index to list logs for 500 | // Displays the logs using `tail` for the specified `target`. 501 | // 502 | app.cmd('logs :index', cli.logs = function (index) { 503 | var options = { 504 | stream: app.argv.fifo, 505 | length: app.argv.number 506 | }; 507 | 508 | forever.tail(index, options, function (err, log) { 509 | if (err) { 510 | return forever.log.error(err.message); 511 | } 512 | 513 | forever.log.data(log.file.magenta + ':' + log.pid + ' - ' + log.line); 514 | 515 | }); 516 | }); 517 | 518 | // 519 | // ### function logFiles () 520 | // Display log files for all running forever processes. 521 | // 522 | app.cmd('logs', cli.logFiles = function (index) { 523 | if (typeof index !== 'undefined') { 524 | return; 525 | } 526 | 527 | var rows = [[' ', 'script', 'logfile']]; 528 | index = 0; 529 | 530 | forever.list(false, function (err, processes) { 531 | if (!processes) { 532 | return forever.log.warn('No forever logfiles in ' + forever.config.get('root').magenta); 533 | } 534 | 535 | forever.log.info('Logs for running Forever processes'); 536 | rows = rows.concat(processes.map(function (proc) { 537 | return ['[' + index++ + ']', proc.file.grey, proc.logFile.magenta]; 538 | })); 539 | 540 | cliff.putRows('data', rows, ['white', 'grey', 'magenta']); 541 | }); 542 | }); 543 | 544 | 545 | app.cmd('columns add :name', cli.addColumn = function (name) { 546 | if (checkColumn(name)) { 547 | var columns = forever.config.get('columns'); 548 | 549 | if (~columns.indexOf(name)) { 550 | return forever.log.warn(name.magenta + ' already exists in forever'); 551 | } 552 | 553 | forever.log.info('Adding column: ' + name.magenta); 554 | columns.push(name); 555 | 556 | forever.config.set('columns', columns); 557 | } 558 | }); 559 | 560 | app.cmd('columns rm :name', cli.rmColumn = function (name) { 561 | if (checkColumn(name)) { 562 | var columns = forever.config.get('columns'); 563 | 564 | if (!~columns.indexOf(name)) { 565 | return forever.log.warn(name.magenta + ' doesn\'t exist in forever'); 566 | } 567 | 568 | forever.log.info('Removing column: ' + name.magenta); 569 | columns.splice(columns.indexOf(name), 1); 570 | 571 | forever.config.set('columns', columns); 572 | } 573 | }); 574 | 575 | app.cmd(/columns set (.*)/, cli.setColumns = function (columns) { 576 | forever.log.info('Setting columns: ' + columns.magenta); 577 | 578 | forever.config.set('columns', columns.split(' ')); 579 | }); 580 | 581 | app.cmd('columns reset', cli.resetColumns = function () { 582 | var columns = 'uid command script forever pid logfile uptime'; 583 | 584 | forever.log.info('Setting columns: ' + columns.magenta); 585 | 586 | forever.config.set('columns', columns.split(' ')); 587 | }); 588 | 589 | // 590 | // ### function help () 591 | // Shows help 592 | // 593 | app.cmd('help', cli.help = function () { 594 | util.puts(help.join('\n')); 595 | }); 596 | 597 | // 598 | // ### function start (file) 599 | // #### @file {string} Location of the script to spawn with forever 600 | // Starts a forever process for the script located at `file` as non-daemon 601 | // process. 602 | // 603 | // Remark: this regex matches everything. It has to be added at the end to 604 | // make executing other commands possible. 605 | // 606 | cli.run = function () { 607 | var file = app.argv._[0], 608 | options = getOptions(file); 609 | 610 | options.forEach(function (o) { 611 | tryStart(o.script, o, function () { 612 | var monitor = forever.start(o.script, o); 613 | monitor.on('start', function () { 614 | forever.startServer(monitor); 615 | }); 616 | }); 617 | }); 618 | }; 619 | 620 | cli.start = function () { 621 | if (app.argv.version) { 622 | return console.log('v' + forever.version); 623 | } 624 | 625 | // 626 | // Check for --no-colors/--colors and --plain option 627 | // 628 | if ((typeof app.argv.colors !== 'undefined' && !app.argv.colors) || app.argv.plain) { 629 | colors.mode = 'none'; 630 | } 631 | 632 | if (app.config.get('help')) { 633 | return util.puts(help.join('\n')); 634 | } 635 | 636 | app.init(function () { 637 | if (app.argv._.length && actions.indexOf(app.argv._[0]) === -1) { 638 | return cli.run(); 639 | } 640 | 641 | app.start(); 642 | }); 643 | }; 644 | -------------------------------------------------------------------------------- /lib/forever/worker.js: -------------------------------------------------------------------------------- 1 | const events = require('events'); 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | const nssocket = require('nssocket'); 5 | const util = require('util'); 6 | const utils = require('../util/utils'); 7 | const forever = require(path.resolve(__dirname, '..', 'forever')); 8 | 9 | const Worker = exports.Worker = function (options) { 10 | events.EventEmitter.call(this); 11 | options = options || {}; 12 | 13 | this.monitor = options.monitor; 14 | this.sockPath = options.sockPath || forever.config.get('sockPath'); 15 | this.exitOnStop = options.exitOnStop === true; 16 | 17 | this._socket = null; 18 | }; 19 | 20 | util.inherits(Worker, events.EventEmitter); 21 | 22 | Worker.prototype.start = function (callback) { 23 | var self = this, 24 | err; 25 | 26 | if (this._socket) { 27 | err = new Error("Can't start already started worker"); 28 | if (callback) { 29 | return callback(err); 30 | } 31 | 32 | throw err; 33 | } 34 | 35 | // 36 | // Defines a simple `nssocket` protocol for communication 37 | // with a parent process. 38 | // 39 | function workerProtocol(socket) { 40 | socket.on('error', function() { 41 | socket.destroy(); 42 | }); 43 | 44 | socket.data(['ping'], function () { 45 | socket.send(['pong']); 46 | }); 47 | 48 | socket.data(['data'], function () { 49 | socket.send(['data'], self.monitor.data); 50 | }); 51 | 52 | socket.data(['spawn'], function (data) { 53 | if (!data.script) { 54 | return socket.send(['spawn', 'error'], { error: new Error('No script given') }); 55 | } 56 | 57 | if (self.monitor) { 58 | return socket.send(['spawn', 'error'], { error: new Error("Already running") }); 59 | } 60 | 61 | var monitor = new (forever.Monitor)(data.script, data.args); 62 | monitor.start(); 63 | 64 | monitor.on('start', function () { 65 | socket.send(['spawn', 'start'], monitor.data); 66 | }); 67 | }); 68 | 69 | socket.data(['stop'], function () { 70 | function onStop(err) { 71 | var args = []; 72 | if (err && err instanceof Error) { 73 | args.push(['stop', 'error'], { message: err.message, stack: err.stack }); 74 | self.monitor.removeListener('stop', onStop); 75 | } 76 | else { 77 | args.push(['stop', 'ok']); 78 | self.monitor.removeListener('error', onStop); 79 | } 80 | 81 | socket.send.apply(socket, args); 82 | if (self.exitOnStop) { 83 | process.exit(); 84 | } 85 | } 86 | 87 | self.monitor.once('stop', onStop); 88 | self.monitor.once('error', onStop); 89 | 90 | if (process.platform === 'win32') { 91 | // 92 | // On Windows, delete the 'symbolic' sock file. This 93 | // file is used for exploration during `forever list` 94 | // as a mapping to the `\\.pipe\\*` "files" that can't 95 | // be enumerated because ... Windows. 96 | // 97 | fs.unlinkSync(self._sockFile); 98 | } 99 | 100 | self.monitor.stop(); 101 | }); 102 | 103 | socket.data(['restart'], function () { 104 | self.monitor.once('restart', function () { 105 | socket.send(['restart', 'ok']); 106 | }); 107 | 108 | self.monitor.restart(); 109 | }); 110 | } 111 | 112 | function findAndStart() { 113 | self._socket = nssocket.createServer(workerProtocol); 114 | self._socket.on('listening', function () { 115 | // 116 | // `listening` listener doesn't take error as the first parameter 117 | // 118 | self.emit('start'); 119 | if (callback) { 120 | callback(null, self._sockFile); 121 | } 122 | }); 123 | 124 | self._socket.on('error', function (err) { 125 | if (err.code === 'EADDRINUSE') { 126 | return findAndStart(); 127 | } 128 | else if (callback) { 129 | callback(err); 130 | } 131 | }); 132 | 133 | // 134 | // Create a unique socket file based on the current microtime. 135 | // 136 | var sock = self._sockFile = path.join(self.sockPath, [ 137 | 'worker', 138 | new Date().getTime() + utils.randomString(3), 139 | 'sock' 140 | ].join('.')); 141 | 142 | if (process.platform === 'win32') { 143 | // 144 | // Create 'symbolic' file on the system, so it can be later 145 | // found via "forever list" since the `\\.pipe\\*` "files" can't 146 | // be enumerated because ... Windows. 147 | // 148 | fs.openSync(sock, 'w'); 149 | 150 | // 151 | // It needs the prefix, otherwise EACCESS error happens on Windows 152 | // (no .sock extension, only named pipes with .pipe prefixes) 153 | // 154 | sock = '\\\\.\\pipe\\' + sock; 155 | } 156 | 157 | self._socket.listen(sock); 158 | } 159 | 160 | // 161 | // Attempt to start the server the first time 162 | // 163 | findAndStart(); 164 | return this; 165 | }; 166 | 167 | -------------------------------------------------------------------------------- /lib/util/config-utils.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var fs = require('fs'); 3 | var Configstore = require('configstore'); 4 | 5 | function initConfigFile(foreverRoot) { 6 | try { 7 | return new Configstore('config', undefined, { 8 | "configPath" : path.join(foreverRoot, 'config.json') 9 | }); 10 | } catch (err) { 11 | return new Configstore() 12 | } 13 | } 14 | 15 | // 16 | // Synchronously create the `root` directory 17 | // and the `pid` directory for forever. Although there is 18 | // an additional overhead here of the sync action. It simplifies 19 | // the setup of forever dramatically. 20 | // 21 | function tryCreateDir(dir) { 22 | try { 23 | if (!fs.existsSync(dir)) { 24 | fs.mkdirSync(dir, '0755'); 25 | } 26 | } 27 | catch (error) { 28 | throw new Error('Failed to create directory '+dir+":" +error.message); 29 | } 30 | } 31 | 32 | module.exports = { 33 | initConfigFile: initConfigFile, 34 | tryCreateDir: tryCreateDir 35 | }; 36 | -------------------------------------------------------------------------------- /lib/util/utils.js: -------------------------------------------------------------------------------- 1 | // 2 | // ### function randomString (length) 3 | // #### @length {integer} The number of bits for the random base64 string returned to contain 4 | // randomString returns a pseude-random ASCII string (subset) 5 | // the return value is a string of length ⌈bits/6⌉ of characters 6 | // from the base64 alphabet. 7 | // 8 | function randomString(length) { 9 | let rand, i, ret, bits; 10 | const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-'; 11 | const mod = 4; 12 | 13 | ret = ''; 14 | // standard 4 15 | // default is 16 16 | bits = length * mod || 64; 17 | 18 | // in v8, Math.random() yields 32 pseudo-random bits (in spidermonkey it gives 53) 19 | while (bits > 0) { 20 | // 32-bit integer 21 | rand = Math.floor(Math.random() * 0x100000000); 22 | //we use the top bits 23 | for (i = 26; i > 0 && bits > 0; i -= mod, bits -= mod) { 24 | ret += chars[0x3f & (rand >>> i)]; 25 | } 26 | } 27 | 28 | return ret; 29 | } 30 | 31 | module.exports = { 32 | randomString, 33 | }; 34 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "forever", 3 | "preferGlobal": "true", 4 | "description": "A simple CLI tool for ensuring that a given node script runs continuously (i.e. forever)", 5 | "version": "4.0.3", 6 | "author": "Charlie Robbins ", 7 | "maintainers": [ 8 | "Igor Savin " 9 | ], 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/foreverjs/forever.git" 13 | }, 14 | "keywords": [ 15 | "cli", 16 | "fault tolerant", 17 | "sysadmin", 18 | "tools" 19 | ], 20 | "dependencies": { 21 | "async": "^1.5.2", 22 | "cliff": "^0.1.10", 23 | "clone": "^2.1.2", 24 | "@colors/colors": "1.5.0", 25 | "configstore": "4.0.0", 26 | "eventemitter2": "6.4.4", 27 | "flatiron": "~0.4.3", 28 | "forever-monitor": "^3.0.3", 29 | "mkdirp": "^0.5.5", 30 | "nssocket": "^0.6.0", 31 | "object-assign": "^4.1.1", 32 | "prettyjson": "^1.2.2", 33 | "shush": "^1.0.0", 34 | "winston": "^3.4.0" 35 | }, 36 | "devDependencies": { 37 | "chai": "^4.2.0", 38 | "cli-testlab": "^1.10.0", 39 | "eslint": "^5.16.0", 40 | "eslint-config-prettier": "^6.11.0", 41 | "eslint-plugin-prettier": "^3.1.3", 42 | "getopts": "2.3.0", 43 | "mocha": "^6.2.2", 44 | "moment": "^2.24.0", 45 | "prettier": "^1.19.1", 46 | "request": "2.88.2", 47 | "vows": "0.7.x" 48 | }, 49 | "bin": { 50 | "forever": "./bin/forever" 51 | }, 52 | "main": "./lib/forever", 53 | "scripts": { 54 | "lint": "eslint \"lib/**/*.js\" \"test/**/*.js\"", 55 | "test": "npm run test:vows && npm run test:mocha", 56 | "test:mocha": "mocha test/mocha/**/*.spec.js", 57 | "test:vows": "vows test/**/*-test.js --dot-matrix -i", 58 | "test:ci": "npm run lint && npm test", 59 | "prettier": "prettier --write \"{lib,examples,test}/**/*.js\"" 60 | }, 61 | "engines": { 62 | "node": ">=6" 63 | }, 64 | "files": [ 65 | "LICENSE", 66 | "CHANGELOG.md", 67 | "README.md", 68 | "bin/*", 69 | "lib/*" 70 | ], 71 | "license": "MIT" 72 | } 73 | -------------------------------------------------------------------------------- /test/cli-test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # 4 | # cli-test: Tests for forever CLI 5 | # 6 | # (C) 2012 Charlie Robbins & the Contributors 7 | # MIT LICENSE 8 | # 9 | 10 | # Yes, we have tests in bash. How mad science is that? 11 | 12 | alias forever=bin/forever 13 | script="test/fixtures/log-on-interval.js" 14 | 15 | function fail { 16 | echo "\033[31m ✘ $1\033[0m" 17 | exit 1 18 | } 19 | 20 | function success { 21 | echo "\033[32m ✔ $1\033[0m" 22 | } 23 | 24 | function spec { 25 | [ $? -eq 0 ] || fail "$1" 26 | success "$1" 27 | } 28 | 29 | echo "\033[1mRunning tests:\033[0m" 30 | 31 | # First kill all processes and remove forever directory to ensure clean 32 | # environment 33 | forever stopall 34 | rm -rf ~/.forever 35 | 36 | # Spawn some process 37 | forever start "$script" 38 | 39 | # Assert that forever actually spawned a process and that it's in `forever list` 40 | sleep 1 # it takes some time until process appears in `forever list` 41 | forever list | grep "$script" 42 | spec "\`forever list\` should contain spawned process" 43 | 44 | # `forever stop` should output process it stopped... 45 | forever stop 0 | grep "$script" 46 | spec "\`forever stop 0\` should contain stopped process" 47 | 48 | # ... and actually stop it 49 | forever list | grep -v "$script" 50 | spec "\`forever stop 0\` should actually stop the process" 51 | 52 | -------------------------------------------------------------------------------- /test/core/daemonic-inheritance-test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * daemonic-inheritance-test.js: Tests for configuration inheritance of forever.startDaemon() 3 | * 4 | * (C) 2010 Charlie Robbins & the Contributors 5 | * MIT LICENCE 6 | * 7 | */ 8 | 9 | var assert = require('assert'), 10 | path = require('path'), 11 | fs = require('fs'), 12 | vows = require('vows'), 13 | forever = require('../../lib/forever'); 14 | 15 | // 16 | // n.b. (indexzero): The default root is `~/.forever` so this 17 | // actually is a valid, non-default test path. 18 | // 19 | var myRoot = path.resolve(process.env.HOME, '.forever_root'); 20 | 21 | vows.describe('forever/core/startDaemon').addBatch({ 22 | "When using forever" : { 23 | "the startDaemon() method with customized configuration" : { 24 | topic: function () { 25 | if (!fs.existsSync(myRoot)) { 26 | fs.mkdirSync(myRoot); 27 | } 28 | 29 | forever.load({root:myRoot}); 30 | 31 | forever.startDaemon(path.join(__dirname, '..', 'fixtures', 'log-on-interval.js')); 32 | setTimeout(function (that) { 33 | forever.list(false, that.callback); 34 | }, 2000, this); 35 | }, 36 | "should respond with 1 process": function (err, procs) { 37 | assert.isNull(err); 38 | assert.isArray(procs); 39 | assert.equal(procs.length, 1); 40 | }, 41 | "and logs/pids/socks are all piping into the customized root": function (err, procs) { 42 | assert.equal(procs[0].logFile.indexOf(myRoot), 0); 43 | assert.equal(procs[0].pidFile.indexOf(myRoot), 0); 44 | assert.equal(procs[0].socket.indexOf(myRoot), 0); 45 | } 46 | } 47 | } 48 | }).addBatch({ 49 | "When the tests are over" : { 50 | "stop all forever processes" : { 51 | topic: function () { 52 | forever.load({root:myRoot}); 53 | forever.stopAll().on('stopAll', this.callback.bind(null, null)); 54 | }, 55 | "should stop the correct number of procs": function (err, procs) { 56 | assert.isArray(procs); 57 | assert.lengthOf(procs, 1); 58 | } 59 | } 60 | } 61 | }).export(module); 62 | -------------------------------------------------------------------------------- /test/core/start-stop-json-array-test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * start-stop-json-test.js: start or stop forever using relative paths, the script path could be start with './', '../' ... 3 | * 4 | * (C) 2010 Charlie Robbins & the Contributors 5 | * MIT LICENCE 6 | * 7 | */ 8 | 9 | var assert = require('assert'), 10 | path = require('path'), 11 | fs = require('fs'), 12 | vows = require('vows'), 13 | async = require('async'), 14 | request = require('request'), 15 | forever = require('../../lib/forever'), 16 | runCmd = require('../helpers').runCmd; 17 | 18 | vows.describe('forever/core/start-stop-json-array').addBatch({ 19 | "When using forever" : { 20 | "to start process using JSON configuration file containing an array" : { 21 | topic: function () { 22 | runCmd('start', [ 23 | './test/fixtures/servers.json' 24 | ]); 25 | setTimeout(function (that) { 26 | forever.list(false, that.callback); 27 | }, 2000, this); 28 | }, 29 | "the startup should works fine": function (err, procs) { 30 | assert.isNull(err); 31 | assert.isArray(procs); 32 | assert.equal(procs.length, 2); 33 | } 34 | } 35 | } 36 | }).addBatch({ 37 | "When the script is running": { 38 | "request to both ports": { 39 | topic: function () { 40 | async.parallel({ 41 | one: async.apply(request, { uri: 'http://localhost:8080', json: true }), 42 | two: async.apply(request, { uri: 'http://localhost:8081', json: true }) 43 | }, this.callback); 44 | }, 45 | "should respond correctly": function (err, results) { 46 | assert.isNull(err); 47 | assert.isTrue(!results.one[1].p); 48 | assert.equal(results.two[1].p, 8081); 49 | } 50 | } 51 | } 52 | }).addBatch({ 53 | "When the script is running" : { 54 | "try to stopall" : { 55 | topic: function () { 56 | runCmd('stopall', []); 57 | setTimeout(function (that) { 58 | forever.list(false, that.callback); 59 | }, 2000, this); 60 | }, 61 | "the shut down should works fine": function (err, procs) { 62 | assert.isNull(err); 63 | assert.isNull(procs); 64 | } 65 | } 66 | } 67 | }).export(module); 68 | -------------------------------------------------------------------------------- /test/core/start-stop-json-obj-test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * start-stop-json-test.js: start or stop forever using relative paths, the script path could be start with './', '../' ... 3 | * 4 | * (C) 2010 Charlie Robbins & the Contributors 5 | * MIT LICENCE 6 | * 7 | */ 8 | 9 | var assert = require('assert'), 10 | path = require('path'), 11 | fs = require('fs'), 12 | vows = require('vows'), 13 | forever = require('../../lib/forever'), 14 | runCmd = require('../helpers').runCmd; 15 | 16 | vows.describe('forever/core/start-stop-json-obj').addBatch({ 17 | "When using forever" : { 18 | "to start process using JSON configuration file containing an object" : { 19 | topic: function () { 20 | runCmd('start', [ 21 | './test/fixtures/server.json' 22 | ]); 23 | setTimeout(function (that) { 24 | forever.list(false, that.callback); 25 | }, 2000, this); 26 | }, 27 | "the startup should works fine": function (err, procs) { 28 | assert.isNull(err); 29 | assert.isArray(procs); 30 | assert.equal(procs.length, 1); 31 | } 32 | } 33 | } 34 | }).addBatch({ 35 | "When the script is running" : { 36 | "try to stop by uid" : { 37 | topic: function () { 38 | runCmd('stop', [ 39 | 'server' 40 | ]); 41 | setTimeout(function (that) { 42 | forever.list(false, that.callback); 43 | }, 2000, this); 44 | }, 45 | "the shut down should works fine": function (err, procs) { 46 | assert.isNull(err); 47 | assert.isNull(procs); 48 | } 49 | } 50 | } 51 | }).export(module); 52 | -------------------------------------------------------------------------------- /test/core/start-stop-relative-test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * start-stop-relative-test.js: start or stop forever using relative paths, the script path could be start with './', '../' ... 3 | * 4 | * (C) 2010 Charlie Robbins & the Contributors 5 | * MIT LICENCE 6 | * 7 | */ 8 | 9 | var assert = require('assert'), 10 | path = require('path'), 11 | fs = require('fs'), 12 | vows = require('vows'), 13 | forever = require('../../lib/forever'), 14 | runCmd = require('../helpers').runCmd; 15 | 16 | vows.describe('forever/core/start-stop-relative').addBatch({ 17 | "When using forever" : { 18 | "to run script with relative script path" : { 19 | topic: function () { 20 | runCmd('start', [ 21 | './test/fixtures/log-on-interval.js' 22 | ]); 23 | setTimeout(function (that) { 24 | forever.list(false, that.callback); 25 | }, 2000, this); 26 | }, 27 | "the startup should works fine": function (err, procs) { 28 | assert.isNull(err); 29 | assert.isArray(procs); 30 | assert.equal(procs.length, 1); 31 | } 32 | } 33 | } 34 | }).addBatch({ 35 | "When the script is running" : { 36 | "try to stop with relative script path" : { 37 | topic: function () { 38 | runCmd('stop', [ 39 | './test/fixtures/log-on-interval.js' 40 | ]); 41 | setTimeout(function (that) { 42 | forever.list(false, that.callback); 43 | }, 2000, this); 44 | }, 45 | "the shut down should works fine": function (err, procs) { 46 | assert.isNull(err); 47 | assert.isNull(procs); 48 | } 49 | } 50 | } 51 | }).export(module); 52 | -------------------------------------------------------------------------------- /test/core/stopall-peaceful-test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * stopall-peaceful-test.js: tests if `forever start` followed by `forever stopall` works. 3 | * 4 | * (C) 2010 Charlie Robbins & the Contributors 5 | * MIT LICENCE 6 | * 7 | */ 8 | 9 | var assert = require('assert'), 10 | path = require('path'), 11 | fs = require('fs'), 12 | spawn = require('child_process').spawn, 13 | vows = require('vows'), 14 | forever = require('../../lib/forever'); 15 | 16 | function runCmd(cmd, args) { 17 | var proc = spawn(process.execPath, [ 18 | path.resolve(__dirname, '../../', 'bin/forever'), 19 | cmd 20 | ].concat(args), {detached: true}); 21 | proc.unref(); 22 | return proc; 23 | } 24 | 25 | vows.describe('forever/core/stopall-peaceful').addBatch({ 26 | "When using forever" : { 27 | "to run script with 100% exit" : { 28 | topic: function () { 29 | runCmd('start', [ 30 | './test/fixtures/cluster-fork-mode.js' 31 | ]); 32 | setTimeout(function (that) { 33 | forever.list(false, that.callback); 34 | }, 2000, this); 35 | }, 36 | "the script should be marked as `STOPPED`": function (err, procs) { 37 | assert.isNull(err); 38 | assert.isArray(procs); 39 | assert.equal(procs.length, 1); 40 | assert.ok(!procs[0].running); 41 | } 42 | } 43 | } 44 | }).addBatch({ 45 | "When the script is running" : { 46 | "try to stop all" : { 47 | topic: function () { 48 | var that = this; 49 | forever.list(false, function(err, procs) { 50 | assert.isNull(err); 51 | assert.isArray(procs); 52 | assert.equal(procs.length, 1); 53 | // get pid. 54 | var pid = procs[0].pid; 55 | // run command 56 | var cmd = runCmd('stopall', []); 57 | cmd.stdout.on('data', onData); 58 | //listen on the `data` event. 59 | function onData(data) { 60 | // check whether pid exists or not. 61 | var line = data.toString().replace (/[\n\r\t\s]+/g, ' '); 62 | if (line && line.search(new RegExp(pid)) > 0) { 63 | that.callback(null, true); 64 | cmd.stdout.removeListener('data', onData); 65 | } 66 | // if pid did not exist, that means CLI has crashed, and no output was printed. 67 | // vows will raise an Asynchronous Error. 68 | } 69 | }); 70 | }, 71 | "the shut down should works fine": function (err, peaceful) { 72 | assert.isNull(err); 73 | assert.ok(peaceful); 74 | } 75 | } 76 | } 77 | }).export(module); -------------------------------------------------------------------------------- /test/core/stopbypid-peaceful-test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * stopbypid-peaceful-test.js: tests if `forever start` followed by `forever stop ` works. 3 | * 4 | * (C) 2010 Charlie Robbins & the Contributors 5 | * MIT LICENCE 6 | * 7 | */ 8 | 9 | var assert = require('assert'), 10 | path = require('path'), 11 | fs = require('fs'), 12 | vows = require('vows'), 13 | forever = require('../../lib/forever'), 14 | runCmd = require('../helpers').runCmd; 15 | 16 | vows.describe('forever/core/stopbypid-peaceful').addBatch({ 17 | "When using forever" : { 18 | "to run script with 100% exit" : { 19 | topic: function () { 20 | runCmd('start', [ 21 | './test/fixtures/log-on-interval.js' 22 | ]); 23 | setTimeout(function (that) { 24 | forever.list(false, that.callback); 25 | }, 2000, this); 26 | }, 27 | "the script should be running": function (err, procs) { 28 | assert.isNull(err); 29 | assert.isArray(procs); 30 | assert.equal(procs.length, 1); 31 | assert.ok(procs[0].running); 32 | } 33 | } 34 | } 35 | }).addBatch({ 36 | "When the script is running" : { 37 | "try to stop by pid" : { 38 | topic: function () { 39 | var that = this; 40 | forever.list(false, function(err, procs) { 41 | assert.isNull(err); 42 | assert.isArray(procs); 43 | assert.equal(procs.length, 1); 44 | // get pid. 45 | var pid = procs[0].pid; 46 | // run command 47 | var cmd = runCmd('stop', [pid]); 48 | cmd.stdout.on('data', onData); 49 | cmd.stderr.pipe(process.stderr); 50 | //listen on the `data` event. 51 | function onData(data) { 52 | // check whether pid exists or not. 53 | var line = data.toString().replace (/[\n\r\t\s]+/g, ' '); 54 | if (line && line.search(new RegExp(pid)) > 0) { 55 | that.callback(null, true); 56 | cmd.stdout.removeListener('data', onData); 57 | } 58 | // if pid did not exist, that means CLI has crashed, and no output was printed. 59 | // vows will raise an Asynchronous Error. 60 | } 61 | }); 62 | }, 63 | "the shut down should works fine": function (err, peaceful) { 64 | assert.isNull(err); 65 | assert.ok(peaceful); 66 | } 67 | } 68 | } 69 | }).export(module); 70 | -------------------------------------------------------------------------------- /test/core/tail-stopall-test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * tail-stopall-test.js: Tests for forever.tail() and forever.stopAll() 3 | * 4 | * (C) 2010 Charlie Robbins & the Contributors 5 | * MIT LICENCE 6 | * 7 | */ 8 | 9 | var assert = require('assert'), 10 | path = require('path'), 11 | spawn = require('child_process').spawn, 12 | vows = require('vows'), 13 | forever = require('../../lib/forever'); 14 | 15 | vows.describe('forever/core/tail').addBatch({ 16 | "When using forever": { 17 | "the tail() method": { 18 | topic: function () { 19 | var that = this; 20 | 21 | that.child = spawn('node', [path.join(__dirname, '..', 'fixtures', 'start-daemon.js')]); 22 | setTimeout(function () { 23 | forever.tail(0, { length: 1 }, that.callback); 24 | }, 2000); 25 | }, 26 | "should respond with logs for the script": function (err, procs) { 27 | assert.isNull(err); 28 | assert.equal(typeof procs, 'object'); 29 | assert.ok(procs.file); 30 | assert.ok(procs.pid); 31 | assert.ok(procs.line); 32 | } 33 | } 34 | } 35 | }).addBatch({ 36 | "When the tests are over": { 37 | "stop all forever processes": { 38 | topic: function () { 39 | forever.stopAll().on('stopAll', this.callback.bind(null, null)); 40 | }, 41 | "should stop the correct number of procs": function (err, procs) { 42 | assert.isArray(procs); 43 | assert.lengthOf(procs, 1); 44 | } 45 | } 46 | } 47 | }).export(module); 48 | -------------------------------------------------------------------------------- /test/core/uptime-test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'), 2 | vows = require('vows'), 3 | moment = require('moment'), 4 | forever = require('../../lib/forever'); 5 | 6 | vows.describe('forever/core/uptime').addBatch({ 7 | "When using forever" : { 8 | "calculates uptime" : { 9 | "for not running process correctly": function (err, procs) { 10 | assert.equal(forever.columns.uptime.get({}), 'STOPPED'.red); 11 | }, 12 | "for running process correctly": function (err, procs) { 13 | var launchTime = moment.utc() 14 | .subtract(4000, 'days') 15 | .subtract(6, 'hours') 16 | .subtract(8, 'minutes') 17 | .subtract(25, 'seconds'); 18 | 19 | var timeWithoutMsecs = forever.columns.uptime.get({ 20 | running: true, 21 | ctime: launchTime.toDate().getTime() 22 | }).strip.split('.')[0]; 23 | 24 | assert.equal(timeWithoutMsecs, '4000:6:8:25'); 25 | } 26 | } 27 | } 28 | }).export(module); 29 | -------------------------------------------------------------------------------- /test/fixtures/cluster-fork-mode.js: -------------------------------------------------------------------------------- 1 | var cluster = require('cluster'); 2 | console.log(cluster.isMaster ? 'master fork':'cluster fork'); -------------------------------------------------------------------------------- /test/fixtures/log-on-interval.js: -------------------------------------------------------------------------------- 1 | setInterval(function () { 2 | console.log('Logging at ' + Date.now()); 3 | }, 100); -------------------------------------------------------------------------------- /test/fixtures/server.js: -------------------------------------------------------------------------------- 1 | var util = require('util'), 2 | http = require('http'), 3 | getopts = require('getopts'); 4 | 5 | var argv = getopts(process.argv.slice(2)); 6 | var port = argv.p || argv.port || 8080; 7 | 8 | http.createServer(function (req, res) { 9 | console.log(req.method + ' request: ' + req.url); 10 | res.writeHead(200, {'Content-Type': 'text/plain'}); 11 | res.write(JSON.stringify(argv)); 12 | res.end(); 13 | }).listen(port); 14 | 15 | /* server started */ 16 | console.log('> hello world running on port ' + port); 17 | -------------------------------------------------------------------------------- /test/fixtures/server.json: -------------------------------------------------------------------------------- 1 | { 2 | "uid": "server", 3 | "append": true, 4 | "script": "server.js", 5 | "sourceDir": "./test/fixtures" 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/servers.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "uid": "server1", 4 | "append": true, 5 | "script": "server.js", 6 | "sourceDir": "./test/fixtures", 7 | "workingDir": "./" 8 | }, 9 | { 10 | "uid": "server2", 11 | "append": true, 12 | "script": "server.js", 13 | "sourceDir": "./test/fixtures", 14 | "workingDir": "./", 15 | "args": ["-p", 8081] 16 | } 17 | ] 18 | -------------------------------------------------------------------------------- /test/fixtures/start-daemon.js: -------------------------------------------------------------------------------- 1 | /* 2 | * start-daemon.js: Simple test fixture for spawning log-on-interval.js as a daemon 3 | * 4 | * (C) 2010 Charlie Robbins & the Contributors 5 | * MIT LICENCE 6 | * 7 | */ 8 | 9 | var path = require('path'), 10 | forever = require('../../lib/forever'); 11 | 12 | var monitor = forever.startDaemon(path.join(__dirname, 'log-on-interval.js')); 13 | 14 | monitor.on('start', function () { 15 | forever.startServer(monitor); 16 | }); 17 | -------------------------------------------------------------------------------- /test/helpers/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * index.js: Test helpers for forever. 3 | * 4 | * (C) 2015 Charlie Robbins & the Contributors 5 | * MIT LICENCE 6 | * 7 | */ 8 | 9 | var path = require('path'), 10 | spawn = require('child_process').spawn; 11 | 12 | /* 13 | * function runCmd (cmd, args) 14 | * Executes forever with the `cmd` and arguments. 15 | */ 16 | exports.runCmd = function runCmd(cmd, args) { 17 | var proc = spawn(process.execPath, [ 18 | path.resolve(__dirname, '../../', 'bin/forever'), 19 | cmd 20 | ].concat(args), {detached: true}); 21 | 22 | // 23 | // Pipe everything to `stderr` so it can 24 | // be seen when running `npm test`. 25 | // 26 | proc.stdout.pipe(process.stderr); 27 | proc.stderr.pipe(process.stderr); 28 | 29 | proc.unref(); 30 | return proc; 31 | } 32 | -------------------------------------------------------------------------------- /test/helpers/macros.js: -------------------------------------------------------------------------------- 1 | /* 2 | * macros.js: Test macros for the forever module 3 | * 4 | * (C) 2010 Charlie Robbins & the Contributors 5 | * MIT LICENCE 6 | * 7 | */ 8 | 9 | var assert = require('assert'), 10 | path = require('path'), 11 | spawn = require('child_process').spawn, 12 | nssocket = require('nssocket'), 13 | forever = require('../../lib/forever'), 14 | Worker = require('../../lib/forever/worker').Worker; 15 | 16 | var macros = exports; 17 | 18 | macros.assertTimes = function (script, times, options) { 19 | options.max = times; 20 | 21 | return { 22 | topic: function () { 23 | var child = new (forever.Monitor)(script, options); 24 | child.on('exit', this.callback.bind({}, null)); 25 | child.start(); 26 | }, 27 | "should emit 'exit' when completed": function (err, child) { 28 | assert.equal(child.times, times); 29 | } 30 | }; 31 | }; 32 | 33 | macros.spawn = function (args, options) { 34 | options.topic = function () { 35 | var self = this; 36 | 37 | args = [path.join(__dirname, '..', 'bin', 'forever')].concat(args); 38 | 39 | var child = spawn(process.argv[0], args), 40 | stdout = '', 41 | stderr = ''; 42 | 43 | child.stdout.on('data', function (data) { 44 | stdout += data; 45 | }); 46 | child.stderr.on('data', function (data) { 47 | stderr += data; 48 | }); 49 | child.once('exit', function (exitCode) { 50 | // 51 | // Remark: We wait 200 ms because of forever boot up time (master 52 | // doesn't wait for slave to start up after it's forked, it just quits) 53 | // 54 | setTimeout(function () { 55 | self.callback(null, exitCode, stdout, stderr); 56 | }, 200); 57 | }); 58 | }; 59 | return options; 60 | }; 61 | 62 | macros.list = function (options) { 63 | options.topic = function () { 64 | forever.list(false, this.callback); 65 | }; 66 | return options; 67 | }; 68 | 69 | macros.assertStartsWith = function (string, substring) { 70 | assert.equal(string.slice(0, substring.length), substring); 71 | }; 72 | 73 | macros.assertList = function (list) { 74 | assert.isNotNull(list); 75 | assert.lengthOf(list, 1); 76 | }; 77 | 78 | macros.assertWorkerConnected = function (workerOptions, batch) { 79 | return { 80 | topic: function () { 81 | var self = this, 82 | reader = new nssocket.NsSocket(), 83 | worker = new Worker(workerOptions); 84 | 85 | worker.start(function (err, sock) { 86 | reader.connect(sock, function () { 87 | self.callback(null, reader, worker, workerOptions); 88 | }); 89 | }); 90 | }, 91 | 'worker should connect': batch 92 | }; 93 | }; 94 | -------------------------------------------------------------------------------- /test/helpers/mocks/child-process.js: -------------------------------------------------------------------------------- 1 | var util = require('util'), 2 | EventEmitter2 = require('eventemitter2').EventEmitter2, 3 | StreamMock = require('./stream').StreamMock; 4 | 5 | var ChildProcessMock = exports.ChildProcessMock = function () { 6 | EventEmitter2.call(this); 7 | 8 | this.stdout = new StreamMock(); 9 | this.stderr = new StreamMock(); 10 | }; 11 | util.inherits(ChildProcessMock, EventEmitter2); 12 | 13 | -------------------------------------------------------------------------------- /test/helpers/mocks/monitor.js: -------------------------------------------------------------------------------- 1 | var util = require('util'), 2 | events = require('eventemitter2'), 3 | ChildProcessMock = require('./child-process').ChildProcessMock; 4 | 5 | var MonitorMock = exports.MonitorMock = function () { 6 | this.child = new ChildProcessMock(); 7 | this.running = false; 8 | }; 9 | util.inherits(MonitorMock, events.EventEmitter2); 10 | 11 | MonitorMock.prototype.__defineGetter__('data', function () { 12 | return { 13 | uid: '_uid', 14 | command: 'node' 15 | }; 16 | }); 17 | 18 | MonitorMock.prototype.kill = MonitorMock.prototype.stop = function (forceStop) { 19 | this.running = false; 20 | 21 | this.emit('stop'); 22 | }; 23 | 24 | -------------------------------------------------------------------------------- /test/helpers/mocks/stream.js: -------------------------------------------------------------------------------- 1 | var util = require('util'), 2 | EventEmitter2 = require('eventemitter2').EventEmitter2; 3 | 4 | var StreamMock = exports.StreamMock = function () { 5 | EventEmitter2.call(this); 6 | 7 | this.contents = []; 8 | this.closed = false; 9 | }; 10 | util.inherits(StreamMock, EventEmitter2); 11 | 12 | StreamMock.prototype.write = function (data) { 13 | this.contents.push(data); 14 | }; 15 | 16 | StreamMock.prototype.close = StreamMock.prototype.end = function () { 17 | this.closed = true; 18 | }; 19 | 20 | -------------------------------------------------------------------------------- /test/helpers/utils.js: -------------------------------------------------------------------------------- 1 | function delayPromise(ms) { 2 | return new Promise(resolve => setTimeout(resolve, ms)); 3 | } 4 | 5 | module.exports = { 6 | delayPromise 7 | } 8 | -------------------------------------------------------------------------------- /test/mocha/cli/cli.spec.js: -------------------------------------------------------------------------------- 1 | const { delayPromise } = require('../../helpers/utils'); 2 | 3 | const { execCommand } = require('cli-testlab'); 4 | 5 | describe('cli', () => { 6 | describe('columns', function () { 7 | this.timeout(5000); 8 | it('manages columns successfully', function () { 9 | return execCommand(`node bin/forever columns reset`, 10 | { 11 | expectedOutput: ['Setting columns:', 'uid command script forever pid logfile uptime'] 12 | }) 13 | .then(function () { 14 | return execCommand(`node bin/forever columns rm uptime`, 15 | { 16 | expectedOutput: ['Removing column:', 'uptime'] 17 | }); 18 | }) 19 | .then(function () { 20 | return execCommand(`node bin/forever columns add uptime`, 21 | { 22 | expectedOutput: ['Adding column:', 'uptime'] 23 | }); 24 | }) 25 | .then(function () { 26 | return execCommand(`node bin/forever columns add uptime`, 27 | { 28 | expectedOutput: ['warn', 'uptime', 'already exists in forever'] 29 | }); 30 | }); 31 | }); 32 | }); 33 | describe('start', () => { 34 | it('starts script successfully', () => { 35 | const oldDir = process.cwd(); 36 | process.chdir('test/mocha/cli/scripts/dir with spaces/'); 37 | return execCommand( 38 | `node ../../../../../bin/forever start script_name.js`, 39 | { 40 | expectedOutput: ['Forever processing file:', 'script_name.js'], 41 | } 42 | ) 43 | .then(() => { 44 | return delayPromise(1000); 45 | }) 46 | .then(() => { 47 | return execCommand(`node ../../../../../bin/forever stopall`, { 48 | expectedOutput: ['Forever stopped processes', 'script_name.js'], 49 | }); 50 | }) 51 | .then(() => { 52 | process.chdir(oldDir); 53 | }); 54 | }); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /test/mocha/cli/scripts/dir with spaces/script_name.js: -------------------------------------------------------------------------------- 1 | console.log('hi there'); 2 | -------------------------------------------------------------------------------- /test/mocha/util/config-utils.spec.js: -------------------------------------------------------------------------------- 1 | const configUtils = require('../../../lib/util/config-utils'); 2 | const fs = require('fs'); 3 | const { expect } = require('chai'); 4 | 5 | describe('config-utils', () => { 6 | describe('tryCreateDir', () => { 7 | it('happy path', () => { 8 | expect(() => { 9 | configUtils.tryCreateDir('happypath'); 10 | }).to.not.throw(); 11 | 12 | expect(fs.existsSync('happypath')).to.equal(true); 13 | fs.rmdirSync('happypath'); 14 | }); 15 | 16 | it('throws an error on invalid directory', () => { 17 | expect(() => { 18 | configUtils.tryCreateDir(''); 19 | }).to.throw( 20 | /Failed to create directory :ENOENT: no such file or directory, mkdir/ 21 | ); 22 | }); 23 | 24 | it('does not fail when creating directory that already exists', () => { 25 | expect(() => { 26 | configUtils.tryCreateDir('dummy'); 27 | configUtils.tryCreateDir('dummy'); 28 | }).to.not.throw(); 29 | fs.rmdirSync('dummy'); 30 | }); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /test/worker/multiple-workers-test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * multiple-workers-test.js: Tests for spawning multiple workers with forever 3 | * 4 | * (C) 2010 Charlie Robbins & the Contributors 5 | * MIT LICENCE 6 | * 7 | */ 8 | 9 | var assert = require('assert'), 10 | net = require('net'), 11 | path = require('path'), 12 | request = require('request'), 13 | vows = require('vows'), 14 | forever = require('../../lib/forever'); 15 | 16 | var children = [], 17 | pids; 18 | 19 | // 20 | // Helper function test requests against children. 21 | // 22 | function assertRunning(port, i) { 23 | return { 24 | topic: function () { 25 | request({ uri: 'http://127.0.0.1:' + port, json: true }, this.callback); 26 | }, 27 | "should respond with `i know nodejitsu`": function (err, res, body) { 28 | assert.isNull(err); 29 | assert.equal(res.statusCode, 200); 30 | assert.equal(body.port, port); 31 | }, 32 | "stop the child process": function () { 33 | children[i].stop(); 34 | } 35 | }; 36 | } 37 | 38 | vows.describe('forever/workers/multiple').addBatch({ 39 | "When using forever": { 40 | "and spawning two processes using the same script": { 41 | topic: function () { 42 | var that = this, 43 | script = path.join(__dirname, '..', 'fixtures', 'server.js'); 44 | 45 | children[0] = new (forever.Monitor)(script, { 46 | silent: true, 47 | maxRestart: 1, 48 | args: [ "--port=8080"] 49 | }); 50 | 51 | children[1] = new (forever.Monitor)(script, { 52 | silent: true, 53 | maxRestart: 1, 54 | args: [ "--port=8081"] 55 | }); 56 | 57 | children[0].on('start', function () { 58 | children[1].on('start', function () { 59 | pids = children.map(function (child) { 60 | return child.child.pid; 61 | }); 62 | 63 | setTimeout(function () { 64 | forever.startServer(children[0], children[1], that.callback); 65 | }, 1000); 66 | }); 67 | 68 | children[1].start(); 69 | }); 70 | 71 | children[0].start(); 72 | }, 73 | "should respond with no error": function (err, workers) { 74 | assert.lengthOf(workers, 2); 75 | assert.equal(workers[0].monitor, children[0]); 76 | assert.equal(workers[1].monitor, children[1]); 77 | workers.forEach(function (worker) { 78 | assert.instanceOf(worker, forever.Worker); 79 | }); 80 | }, 81 | "requests against the first child": assertRunning(8080, 0), 82 | "requests against the second child": assertRunning(8081, 1) 83 | // 84 | // TODO: We should cleanup these processes. 85 | // 86 | } 87 | }, 88 | }).addBatch({ 89 | "Once the stop attempt has been made": { 90 | topic: function () { 91 | setTimeout(this.callback, 200); 92 | }, 93 | "the processes should be dead": function () { 94 | assert.isFalse(forever.checkProcess(pids[0])); 95 | assert.isFalse(forever.checkProcess(pids[1])); 96 | } 97 | } 98 | }).export(module); 99 | -------------------------------------------------------------------------------- /test/worker/simple-test.js: -------------------------------------------------------------------------------- 1 | var path = require('path'), 2 | assert = require('assert'), 3 | vows = require('vows'), 4 | nssocket = require('nssocket'), 5 | macros = require('../helpers/macros'), 6 | MonitorMock = require('../helpers/mocks/monitor').MonitorMock; 7 | 8 | var SOCKET_PATH = path.join(__dirname, '..', 'fixtures'); 9 | 10 | vows.describe('forever/worker/simple').addBatch({ 11 | 'When using forever worker': { 12 | 'and starting it and pinging it': macros.assertWorkerConnected({ 13 | monitor: new MonitorMock(), 14 | sockPath: SOCKET_PATH 15 | }, { 16 | 'and respond to pings': { 17 | topic: function (reader) { 18 | reader.send(['ping']); 19 | reader.data(['pong'], this.callback); 20 | }, 21 | 'with `pong`': function () {} 22 | }, 23 | 'and when queried for data': { 24 | topic: function (reader, _, options) { 25 | var self = this; 26 | 27 | reader.send(['data']); 28 | reader.data(['data'], function (data) { 29 | self.callback(null, { data: data, monitor: options.monitor }); 30 | }); 31 | }, 32 | 'it should respond with data': function (obj) { 33 | assert.isObject(obj.data); 34 | assert.deepEqual(obj.data, obj.monitor.data); 35 | } 36 | }, 37 | 'and when asked to kill the process': { 38 | topic: function (reader, _, options) { 39 | var self = this; 40 | 41 | options.monitor.running = true; 42 | reader.send(['stop']); 43 | reader.data(['stop', 'ok'], function () { 44 | self.callback(null, options.monitor); 45 | }); 46 | }, 47 | 'it should kill the process': function (monitor) { 48 | assert.isFalse(monitor.running); 49 | } 50 | }, 51 | 'and when quickly sending data and disconnecting': { 52 | topic: function(reader) { 53 | var self = this; 54 | 55 | // Need to connect second reader, otherwise it breaks the other 56 | // tests as the reader is shared with them. 57 | var reader2 = new nssocket.NsSocket(); 58 | reader2.connect(reader.host, function() { 59 | reader2.send(['data']); 60 | reader2.destroy(); 61 | 62 | self.callback(); 63 | }); 64 | }, 65 | 'it should not crash the worker': function(worker) { 66 | // no asserition, everything is good if the test does not cause 67 | // a worker crash. 68 | } 69 | } 70 | }) 71 | } 72 | }).export(module); 73 | 74 | --------------------------------------------------------------------------------