32 votes

Exécuter un programme Ruby comme un service Windows ?

Est-il possible d'exécuter une application ruby comme un service Windows ? Je vois qu'il y a une question connexe qui traite de l'exécution d'une application ruby en tant que service Windows. Application Java en tant que service Windows comment faire cela avec une application Ruby ?

25voto

mwilliams Points 6748

Consultez la bibliothèque suivante : Win32Utils . Vous pouvez créer un service simple que vous pouvez démarrer/arrêter/redémarrer à votre guise. Je l'utilise actuellement pour gérer une instance Mongrel pour une application Rails hébergée sous Windows et cela fonctionne parfaitement.

Vous pouvez également utiliser cet exemple comme une méthode pour permettre à votre application Ruby d'agir comme un service Windows : Exécution en tant que service Windows .

Bonne chance.

16voto

Jonke Points 4350

Lorsqu'on essaie les Win32Utils, il faut vraiment étudier la documentation et chercher sur le net avant de trouver un exemple simple et fonctionnel. Cela semble fonctionner aujourd'hui 2008-10-02 :

gem install win32-service

Mise à jour 2012-11-20 : Selon http://stackoverflow.com/users/1374569/paul le fichier register_bar.rb devrait maintenant être

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

créer l'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 est le service mais nous devons d'abord le créer et l'enregistrer ! ceci peut être fait avec sc create some_service

mais si nous voulons utiliser ruby et win32utils, nous devrions faire une

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

Notez qu'il y a un espace entre les c : \tmp\ bar.rb dans 'c : \usr\ruby\bin\rubyw.exe -C c : \tmp\ bar.rb

Exécuter ruby register_bar.rb et maintenant on peut démarrer le service soit à partir du panneau de contrôle des services de Windows, soit

sc start some_service

et regardez c:test.log se remplir avec Le service fonctionne Thu Oct 02 22:06:47 +0200 2008

Pour le simple fait d'avoir quelque chose sur lequel travailler, il est plus facile de supprimer le registre de service et d'en créer un nouveau plutôt que de modifier un registre existant.

unregister_bar.rb

 require "rubygems"
    require "win32/service"
       include Win32

    Service.delete("some_service")

Crédits aux personnes http://rubypane.blogspot.com/2008/05/Windows-service-using-win32-service-and_29.html

http://rubyforge.org/docman/view.php/85/595/service.html

4voto

raubarede Points 136

Voici un modèle de code pour faire du 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

0voto

Ken Points 1693

Vous pouvez écrire (ou télécharger) un service wrapper. Le wrapper peut appeler ruby.exe pour exécuter votre programme. La même astuce fonctionne pour Java, VB, etc.

0voto

GEOCHET Points 13787

Vous devriez être en mesure d'accomplir cela dans IronRuby puisque vous disposez du cadre .NET.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X