Running a Ruby Program as a Windows Service?

前端 未结 5 699
不思量自难忘°
不思量自难忘° 2020-12-02 05:47

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

相关标签:
5条回答
  • 2020-12-02 06:03

    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'       )
    

    bar.rb

    create the application/daemon

    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

    but if we are going to use ruby and win32utils we should do a

    register_bar.rb

     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

    For the simple of have something to work with it is easier to remove the service register and create a new one instead of modifying a existing one

    unregister_bar.rb

     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

    0 讨论(0)
  • 2020-12-02 06:04

    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
    
    0 讨论(0)
  • 2020-12-02 06:13

    You should be able to accomplish this in IronRuby since you would have the .NET framework behind you.

    0 讨论(0)
  • 2020-12-02 06:17

    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.

    0 讨论(0)
  • 2020-12-02 06:22

    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.

    0 讨论(0)
提交回复
热议问题