Browse files

daemonic

  • Loading branch information...
0 parents commit 755b5f6190e376fa7a3b72bd4d8eced55a46ea3c @chjj committed Apr 10, 2012
Showing with 267 additions and 0 deletions.
  1. +19 −0 LICENSE
  2. +55 −0 README.md
  3. +1 −0 index.js
  4. +180 −0 lib/daemonic.js
  5. +12 −0 package.json
19 LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2012, Christopher Jeffrey (https://github.com/chjj/)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
55 README.md
@@ -0,0 +1,55 @@
+# Daemonic
+
+A dead-simple module to daemonize your node process. No compilation required.
+
+## Usage
+
+``` js
+// Daemonize current process.
+require('daemonic')({
+ umask: true, // umask(0);
+ cd: true // chdir("/");
+});
+
+setInterval(function() {
+ console.log('My app is now daemonized. You won\'t see this message.');
+}, 2000);
+```
+
+``` js
+// Daemonize current process, depending
+// on whether certain options are present.
+// Start with: $ myapp --daemonize
+
+var daemonic = require('daemonic')({
+ options: ['--daemonize', '--production'],
+ umask: true,
+ cd: true
+});
+
+setInterval(function() {
+ if (daemonic.daemon) {
+ console.log('My app is now daemonized. You won\'t see this message.');
+ } else {
+ console.log(
+ 'My app didn\'t want to be daemonized.',
+ 'You will see this message.');
+ }
+}, 2000);
+```
+
+``` js
+// Daemonize a specified process.
+// Does not kill (grand)parent.
+require('daemonic')({
+ process: ['node', './myotherapp.js'],
+ umask: true,
+ cd: true
+}, function(err, pid) {
+ console.log('Daemonized: ' + pid);
+});
+```
+
+## License
+
+Copyright (c) 2012, Christopher Jeffrey (MIT License).
1 index.js
@@ -0,0 +1 @@
+module.exports = require('./lib/daemonic');
180 lib/daemonic.js
@@ -0,0 +1,180 @@
+/**
+ * daemonic.js
+ * Daemons for node.
+ * Copyright (c) 2012, Christopher Jeffrey
+ */
+
+/**
+ * Daemonize
+ */
+
+function daemonize(opt, func) {
+ if (opt.process) return daemonize.experimental(opt, func);
+
+ var argv = process.argv.slice()
+ , i;
+
+ if (exports.daemon) return;
+
+ i = process.argv.indexOf(exports.arg);
+ if (~i) {
+ process.argv.splice(i, 1);
+ exports.daemon = true;
+ return;
+ }
+
+ argv.push(exports.arg);
+
+ var spawn = require('child_process').spawn
+ , code = ''
+ , ps;
+
+ // escape arguments
+ argv = argv.map(function(arg) {
+ arg = arg.replace(/(["$\\])/g, '\\$1');
+ return '"' + arg + '"';
+ }).join(' ');
+
+ if (opt.cd) code += 'cd / && ';
+ if (opt.umask) code += 'umask 0 && ';
+
+ code = '('
+ + code
+ + 'setsid '
+ + argv
+ + ' < /dev/null > /dev/null 2>&1 &)';
+
+ ps = spawn('/bin/sh', [ '-c', code ]);
+
+ ps.on('exit', function(code) {
+ process.exit(code || 0);
+ });
+
+ // kill current stack
+ process.once('uncaughtException', function() {});
+ throw 'stop';
+}
+
+daemonize.experimental = function(opt, func) {
+ var argv = opt.process || process.argv.slice()
+ , i;
+
+ if (!opt.process) {
+ if (exports.daemon) return;
+
+ i = process.argv.indexOf(exports.arg);
+ if (~i) {
+ process.argv.splice(i, 1);
+ exports.daemon = true;
+ return;
+ }
+
+ argv.push(exports.arg);
+ }
+
+ var spawn = require('child_process').spawn
+ , code = ''
+ , ps;
+
+ // escape arguments
+ argv = argv.map(function(arg) {
+ arg = arg.replace(/(["$\\])/g, '\\$1');
+ return '"' + arg + '"';
+ }).join(' ');
+
+ if (opt.cd) code += 'cd / && ';
+ if (opt.umask) code += 'umask 0 && ';
+
+ // dup2
+ // should work...
+ // e.g.
+ // $ sh -c '(echo hi 1>&3 &)' 3>&1
+ opt.stdin = opt.stdin != null
+ ? ' 0 <& ' + opt.stdin
+ : ' 0 < /dev/null';
+ opt.stdout = opt.stdout != null
+ ? ' 1 >& ' + opt.stdout
+ : ' 1 > /dev/null';
+ opt.stderr = opt.stderr != null
+ ? ' 2 >& ' + opt.stderr
+ : ' 2 > /dev/null';
+
+ code = '('
+ + code
+ + 'setsid '
+ + argv
+ + opt.stdin
+ + opt.stdout
+ + opt.stderr
+ + ' & echo $!)';
+
+ ps = spawn('/bin/sh', [ '-c', code ]);
+
+ if (opt.process) {
+ // something like:
+ //obj.stdin = createSocket(createPipe(), false);
+ //obj.stdout = createSocket(createPipe(), true);
+ //obj.stderr = createSocket(createPipe(), true);
+ // use these fd's instea of raw fd's in options
+ var pid = '';
+ ps.stdout.on('data', function(data) {
+ pid += data;
+ });
+ ps.on('error', func || function() {});
+ ps.on('exit', function() {
+ if (func) func(null, +pid);
+ });
+ return;
+ }
+
+ ps.on('exit', function(code) {
+ process.exit(code || 0);
+ });
+
+ // kill current stack
+ process.once('uncaughtException', function() {});
+ throw 'stop';
+};
+
+/**
+ * Daemonic
+ */
+
+function daemonic(opt, func) {
+ if (process.platform === 'win32') return;
+
+ var opt = opt || {}
+ , options = opt.options;
+
+ if (options && options.length) {
+ var found = false
+ , argv = process.argv
+ , l = options.length
+ , i = 0
+ , j;
+
+ for (; i < l; i++) {
+ j = argv.indexOf(options[i]);
+ if (~j) {
+ argv.splice(j, 1);
+ found = true;
+ }
+ }
+
+ if (!found) return;
+ }
+
+ daemonize(opt, func);
+
+ return daemonic;
+}
+
+/**
+ * Expose
+ */
+
+exports = daemonic;
+exports.argv = process.argv.slice();
+exports.arg = '--__daemonized__';
+
+module.exports = exports;
12 package.json
@@ -0,0 +1,12 @@
+{
+ "name": "daemonic",
+ "description": "A dead-simple module to daemonize node",
+ "author": "Christopher Jeffrey",
+ "version": "0.0.1",
+ "main": "./index.js",
+ "repository": "git://github.com/chjj/daemonic.git",
+ "homepage": "https://github.com/chjj/daemonic",
+ "bugs": { "url": "https://github.com/chjj/daemonic/issues" },
+ "keywords": [ "daemon", "fork" ],
+ "tags": [ "daemon", "fork" ]
+}

0 comments on commit 755b5f6

Please sign in to comment.