Is it possible to run a ruby application as a Windows Service? I see that there is a related question which discusses running a Java Application as a Windows Service, how c
When trying the Win32Utils one really need to studie the doc and look over the net before finding some simple working example. This seems to work today 2008-10-02:
gem install win32-service
Update 2012-11-20: According to https://stackoverflow.com/users/1374569/paul the register_bar.rb should now be
Service.create( :service_name => 'some_service',
:host => nil,
:service_type => Service::WIN32_OWN_PROCESS,
:description => 'A custom service I wrote just for fun',
:start_type => Service::AUTO_START,
:error_control => Service::ERROR_NORMAL,
:binary_path_name => 'c:\usr\ruby\bin\rubyw.exe -C c:\tmp\ bar.rb',
:load_order_group => 'Network',
:dependencies => ['W32Time','Schedule'],
:display_name => 'This is some service' )
LOG_FILE = 'C:\\test.log'
begin
require "rubygems"
require 'win32/daemon'
include Win32
class DemoDaemon < Daemon
def service_main
while running?
sleep 10
File.open("c:\\test.log", "a"){ |f| f.puts "Service is running #{Time.now}" }
end
end
def service_stop
File.open("c:\\test.log", "a"){ |f| f.puts "***Service stopped #{Time.now}" }
exit!
end
end
DemoDaemon.mainloop
rescue Exception => err
File.open(LOG_FILE,'a+'){ |f| f.puts " ***Daemon failure #{Time.now} err=#{err} " }
raise
end
bar.rb is the service but we must create and register first! this can be done with sc create some_service
require "rubygems"
require "win32/service"
include Win32
# Create a new service
Service.create('some_service', nil,
:service_type => Service::WIN32_OWN_PROCESS,
:description => 'A custom service I wrote just for fun',
:start_type => Service::AUTO_START,
:error_control => Service::ERROR_NORMAL,
:binary_path_name => 'c:\usr\ruby\bin\rubyw.exe -C c:\tmp\ bar.rb',
:load_order_group => 'Network',
:dependencies => ['W32Time','Schedule'],
:display_name => 'This is some service'
)
Note, there is a space between c:\tmp\ bar.rb in 'c:\usr\ruby\bin\rubyw.exe -C c:\tmp\ bar.rb'
Run ruby register_bar.rb
and now one can start the service either from the windows service control panel or
sc start some_service
and watch c:test.log be filled with Service is running Thu Oct 02 22:06:47 +0200 2008
require "rubygems"
require "win32/service"
include Win32
Service.delete("some_service")
Credits to the people http://rubypane.blogspot.com/2008/05/windows-service-using-win32-service-and_29.html
http://rubyforge.org/docman/view.php/85/595/service.html
Here is a code template to do firedeamon :)
#####################################################################
# runneur.rb : service which run (continuously) a process
# 'do only one simple thing, but do it well'
#####################################################################
# Usage:
# .... duplicate this file : it will be the core-service....
# .... modify constantes in beginning of this script....
# .... modify stop_sub_process() at end of this script for clean stop of sub-application..
#
# > ruby runneur.rb install foo ; foo==name of service,
# > ruby runneur.rb uninstall foo
# > type d:\deamon.log" ; runneur traces
# > type d:\d.log ; service traces
#
#####################################################################
class String; def to_dos() self.tr('/','\\') end end
class String; def from_dos() self.tr('\\','/') end end
rubyexe="d:/usr/Ruby/ruby19/bin/rubyw.exe".to_dos
# example with spawn of a ruby process...
SERVICE_SCRIPT="D:/usr/Ruby/local/text.rb"
SERVICE_DIR="D:/usr/Ruby/local".to_dos
SERVICE_LOG="d:/d.log".to_dos # log of stdout/stderr of sub-process
RUNNEUR_LOG="d:/deamon.log" # log of runneur
LCMD=[rubyexe,SERVICE_SCRIPT] # service will do system('ruby text.rb')
SLEEP_INTER_RUN=4 # at each dead of sub-process, wait n seconds before rerun
################### Installation / Desintallation ###################
if ARGV[0]
require 'win32/service'
include Win32
name= ""+(ARGV[1] || $0.split('.')[0])
if ARGV[0]=="install"
path = "#{File.dirname(File.expand_path($0))}/#{$0}".tr('/', '\\')
cmd = rubyexe + " " + path
print "Service #{name} installed with\n cmd=#{cmd} ? " ; rep=$stdin.gets.chomp
exit! if rep !~ /[yo]/i
Service.new(
:service_name => name,
:display_name => name,
:description => "Run of #{File.basename(SERVICE_SCRIPT.from_dos)} at #{SERVICE_DIR}",
:binary_path_name => cmd,
:start_type => Service::AUTO_START,
:service_type => Service::WIN32_OWN_PROCESS | Service::INTERACTIVE_PROCESS
)
puts "Service #{name} installed"
Service.start(name, nil)
sleep(3)
while Service.status(name).current_state != 'running'
puts 'One moment...' + Service.status(name).current_state
sleep 1
end
while Service.status(name).current_state != 'running'
puts ' One moment...' + Service.status(name).current_state
sleep 1
end
puts 'Service ' + name+ ' started'
elsif ARGV[0]=="desinstall" || ARGV[0]=="uninstall"
if Service.status(name).current_state != 'stopped'
Service.stop(name)
while Service.status(name).current_state != 'stopped'
puts 'One moment...' + Service.status(name).current_state
sleep 1
end
end
Service.delete(name)
puts "Service #{name} stopped and uninstalled"
else
puts "Usage:\n > ruby #{$0} install|desinstall [service-name]"
end
exit!
end
#################################################################
# service runneur : service code
#################################################################
require 'win32/daemon'
include Win32
Thread.abort_on_exception=true
class Daemon
def initialize
@state='stopped'
super
log("******************** Runneur #{File.basename(SERVICE_SCRIPT)} Service start ***********************")
end
def log(*t)
txt= block_given?() ? (yield() rescue '?') : t.join(" ")
File.open(RUNNEUR_LOG, "a"){ |f| f.puts "%26s | %s" % [Time.now,txt] } rescue nil
end
def service_pause
#put activity in pause
@state='pause'
stop_sub_process
log { "service is paused" }
end
def service_resume
#quit activity from pause
@state='run'
log { "service is resumes" }
end
def service_interrogate
# respond to quistion status
log { "service is interogate" }
end
def service_shutdown
# stop activities before shutdown
log { "service is stoped for shutdown" }
end
def service_init
log { "service is starting" }
end
def service_main
@state='run'
while running?
begin
if @state=='run'
log { "starting subprocess #{LCMD.join(' ')} in #{SERVICE_DIR}" }
@pid=::Process.spawn(*LCMD,{
chdir: SERVICE_DIR,
out: SERVICE_LOG, err: :out
})
log { "sub-process is running : #{@pid}" }
a=::Process.waitpid(@pid)
@pid=nil
log { "sub-process is dead (#{a.inspect})" }
sleep(SLEEP_INTER_RUN) if @state=='run'
else
sleep 3
log { "service is sleeping" } if @state!='run'
end
rescue Exception => e
log { e.to_s + " " + e.backtrace.join("\n ")}
sleep 4
end
end
end
def service_stop
@state='stopped'
stop_sub_process
log { "service is stoped" }
exit!
end
def stop_sub_process
::Process.kill("KILL",@pid) if @pid
@pid=nil
end
end
Daemon.mainloop
You should be able to accomplish this in IronRuby since you would have the .NET framework behind you.
Check out the following library: Win32Utils. You can create a simple service that you can start/stop/restart at your leisure. I'm currently using it to manage a Mongrel instance for a Windows hosted Rails app and it works flawlessly.
You can write (or download) a wrapper service. The wrapper can call the ruby.exe to execute your program. Same trick works for Java, VB, etc.