`
Joson_Coney
  • 浏览: 57931 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

【转】Writing Daemons in Javascript with node.JS

 
阅读更多

April 1, 2010

Writing Daemons in Javascript with node.JS

At some point, while developing a web-framework with node.js, I thought it would be nice if I could create Daemons in Javascript(no wrappers!). So I've created this very simple module for node.js. It's called daemon.nodeBasically, it makes system calls that are required to create a working daemon.

Before I jump in explaining how it works and how to use it, I want to show you how simple it is to create a daemon with this module.

 

That's it. Just require() the daemon module and call daemon.start(). Of course, it's an oversimplified example, but it is going to produce a working daemon. I'll try to show you more useful examples below.

What is a daemon and how to create it..

Basically, a daemon is a process that runs in the background. I'm not going to talk about Windows daemons(they're called services), but rather focus on traditional *nix daemons.

Without going into the details, in order to become a daemon, a program goes through these steps:

  1. fork() from a parent process.
  2. Terminate parent process.
  3. Create new session with setsid().
This is the minimum requirement for a daemon. If any of these steps fail, the process won't become a daemon.
Now, it is preferred for a daemon to take these additional steps:
  1. umask() sets file mode creation mask.
  2. chdir() sets working directory.
  3. Close stdin, stdout, stderr. The preferred way is to use logging(custom or syslog).
Basically, the daemon.start() function forks, kills parent, creates new session, umasks, chdirs.
In order to close stdin, stdout and stderr, you will have to calldaemon.closeIO() function.
By default, umask() is called with the first argument set to 0, and chdir() changes working directory to the root "/". After daemon has been created you can use node's built in functions to alter these settings to your needs: process.umask andprocess.chdir.
Here's an example:

 

 

There's one problem though. How do you know that only one instance of your daemon will be started? The traditional way for this is to use file locks. Daemon creates a file lock. Common convention is to use "/tmp/[daemon_name].lock" or "/var/run/[daemon_name].pid". Then daemon usually writes its own PID to that file, as it can be useful. When daemon terminates it will automatically unlock the file and a new daemon can be started. To create a lock file, you use a module functiondaemon.lock([filename]). if [filename] doesn't exist, the function creates it automatically.

 

Example: HTTP-Server daemon.
Here is a complete(well, almost complete) implementation of our hellohttpd.

 

It's pretty simple and straightforward, so I won't go into explanations here. Now, this example still doesn't implement signal handling. Basically, you would want to handle these two signals SIGHUP and SIGTERM. Many servers use SIGHUP to restart, so it's a good idea to do some serialization, etc. work there. To catch these signals, you should use process.addListener("SIGTERM", function() { ... } );
Hope, you'll find it useful. :)

Comments (12)

Apr 02, 2010
HB said...
Thanks for this simple module and great explanation of how it works. I'll be trying this out this weekend for sure!
Apr 03, 2010
【转】Writing <wbr>Daemons <wbr>in <wbr>Javascript <wbr>with <wbr>node.JS
Arthur said...
@HB I hope it works you. Let me know if you have any trouble.
Thanks.
Apr 06, 2010
nefD said...
Thanks muchly for this! Solves roughly three deployment issues for me.. Here's hoping it will continue to be updated or stay compatible with the rapidly released node updates. :)
Apr 08, 2010
【转】Writing <wbr>Daemons <wbr>in <wbr>Javascript <wbr>with <wbr>node.JS
Arthur said...
@nefD It should be compatible with future releases as it depends rather on how V8 works, but I'll try to keep it up-to-date. I'm very glad it was useful for you.
May 31, 2010
satori said...
Hi, when I run your example it runs without errors, but any type of server that is started in the forked process never returns any data to my client.

The same script runs fine if I comment out the daemon module lines, and I can connect to my servers.

Is there any obvious reason why I connect to, but not receive data from, any node server running in the daemon forked process?

May 31, 2010
satori said...
I worked this out. Calling daemon.closeIO() stops my node server in the forked process from receiving any new requests. Connections are accepted, but no new requests are fired.

If I remove the call to closeIO(), it works as advertised.

Not sure if this is a problem with my system, node,v8, or daemon.node.

Jun 15, 2010
Francisco said...
Nice module! But something strange occurs sometimes... it writes the pid in the lock file, but the process id is actually one digit less.

Example: fs.readFileSync(lockFile).toString() => 17284

ps -ef | grep node =>
admin 1728 1 0 18:26 ? 00:00:01 node app/app.js start

So then when invoking stop, it obviously does not find the process:

/home/admin/www/testing/app/app.js:15
process.kill(parseInt(fs.readFileSync(pidFile)));
^
Error: No such process
at Object.<anonymous> (/home/admin/www/testing/app/app.js:15:11)
at Module._compile (module:384:23)
at Module._loadScriptSync (module:393:8)
at Module.loadSync (module:296:10)
at Object.runMain (module:447:22)
at node.js:208:10

Using node 0.1.98 on Ubuntu. It doesn't seem to happen on Snow Leopard. Any ideas?

Jun 30, 2010
Wayne said...
@Francisco

The pid in the tempfile is wrong in your case because the pidfile is not deleted on each run, the file is not opened with O_TRUNC set, and pid values can be different lengths over time. So, when pid values roll over from longer to shorter, if your old pidfile had a long value in it then an incorrect value will be written.

The solution is to patch LockD() in daemon.cc to include O_TRUNC option on open().

Sep 06, 2010
Ryan said...
Exactly what I was looking for, but unfortunately I can't seem to get it to work. When trying to daemonize, I get the error:

(libev) kevent: Bad file descriptor

Since the error is so generic, I'm not sure what would be causing it. I followed the example code closely as well. Any ideas? Thanks!

Oct 06, 2010
Kip said...
http://utahjs.com/2010/09/24/running-a-nodejs-server-as-a-daemon-on-ubuntu/

Thanks! Your module was very useful for me!

See my guide on using this with Ubuntu... it really would work for any unix based distribution.

Oct 14, 2010
【转】Writing <wbr>Daemons <wbr>in <wbr>Javascript <wbr>with <wbr>node.JS
tajur said...
It seems daemon-node is not properly working on Mac OS X. I also get this error: "(libev) kevent: Bad file descriptor" when trying to start a daemon. Seems to be related to kqueue, but the error is pretty generic and won't help much at debugging.

Any clue on how to address this?

Nov 04, 2010
dswift said...
Instead of closing the streams in this module, you should probably just redirect them, so that you can still process connections.

freopen( "/dev/null", "r", stdin);
freopen( "/dev/null", "w", stdout);
freopen( "/dev/null", "w", stderr);

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics