From: Guillaume Marcais Date: 2006-03-19T05:21:11+09:00 Subject: Re: How to write a Ruby service(?)? Le 18 mars 06, � 08:19, Randy Kramer a �crit : > I need to write what might be called a Ruby service or server(?)--a > Ruby > program that: > * runs only one instance even if "invoked" multiple times > * can be sent additional "commands" via CLI commands, e.g., if the > name of > the program is, for example, "program" I can issue multiple CLI > commands > like: > > program > > If program is not running, it will start and perform appropriate > actions based > on the parameters. > > If program is running, the existing instance of the program will > receive those > parameters and perform appropriate actions. > > At the moment (and maybe permanently ;-) I'm drawing a blank as to > what a > program like that is called (service, server, ...?), and where to dig > to > learn how to implement such a thing (preferably in Ruby). > > Hints? > > Initially I plan to implement this under Linux--some day it may get > ported to > Windows, etc. I have some code that do kind of what you are describing. But I have to admit that lately, when I run a daemon/service on my Linux box, I am incline to manage it with something like runit (http://smarden.sunsite.dk/runit/). I find it easier than to manage than the SysV services. On to some code. The server says: module TelnetShellServer def self.daemonize return true if fork # Parent exits, child continues. Process.setsid # Become session leader. exit if fork # Zap session leader. See [1]. Dir.chdir "/" # Release old working directory. File.umask 0000 # Ensure sensible umask. Adjust as needed. STDIN.reopen("/dev/null", "r") # Free file descriptors and stdout_r, stdout_w = IO.pipe stderr_r, stderr_w = IO.pipe Thread.new { loop { $logger.info(stdout_r.gets.chomp) } } Thread.new { loop { $logger.error(stderr_r.gets.chomp) } } STDOUT.reopen(stdout_w) STDERR.reopen(stderr_w) nil end class Broker [... actual useful service code ...] end end [ ... read options and configuration file ...] unless foreground TelnetShellServer.daemonize and exit 0 end $SAFE = 1 # disable eval() and friends BROKER = Broker.new(login_files, auto_kill) $logger.info("Starting DRb") DRb.start_service(uri.to_s, BROKER) $logger.info("Broker listening at #{uri}") trap("TERM") { $logger.debug("TERM"); BROKER.stop } trap("QUIT") { $logger.debug("QUIT"); BROKER.stop } trap("INT") { $logger.debug("INT"); BROKER.stop } trap("HUP") { $logger.debug("HUP"); BROKER.reread_logins } DRb.thread.join The client says: [ ... read options and configuration file ...] uri = URI.parse(uri) DRb.start_service broker = DRbObject.new_with_uri(uri.to_s) tries = 2 host, cmd = ARGV.shift, ARGV.join(' ') begin res = broker.connection_do(host, cmd) puts(res) if res rescue DRb::DRbConnError if auto_vivify && ((tries -= 1) > 0) system("telnet_shell_serverd") # server not present, start it! sleep(2) retry end raise end HTH, Guillaume. > > Thanks! > Randy Kramer > > Incidentally, if the program crashes, the next invocation of the > program will > restart it and recover as much of the previous "context" as possible > (which > is, of course, only what has been recorded to disk). > >