ruby 实现windows service启动和关闭 nginx和jruby trinidad

问题:单位只给windows server,部署环境被迫使用 jruby trinidad + nginx + mongodb,每次启动app需要开4个窗口(2个jruby)。共用的服务器经常被人关窗口,服务器重启后需手动启动。

解决办法:写windows 服务。

1. 使用win32-service gem。

需要本地编译。

gem install win32-service。

文档见http://win32utils.rubyforge.org/

2.编写服务

服务分为两个部分,一是service 安装和卸载的部分。另一部分为服务内容部分。

可参照

http://stackoverflow.com/questions/163497/running-a-ruby-program-as-a-windows-service

简化版的service 安装部分如下:

require "win32/service"
include Win32
class String; def to_dos() self.tr('/','\\') end end
class String; def from_dos() self.tr('\\','/') end end
#override to support utf8
class String; def strip() self end end

rubyexe="C:/bin/ruby.exe".to_dos
SERVICE_FILE= (File.expand_path(File.dirname(File.dirname(__FILE__)))+ '/service.rb').to_dos
SERVICE_NAME="Test Service"

if ARGV[0]
  case ARGV[0] 
  when "install" 
    Service.new(
      :service_name     => SERVICE_NAME, 
      :service_type       => Service::WIN32_OWN_PROCESS,
      :start_type         => Service::AUTO_START,
      :error_control      => Service::ERROR_NORMAL,
      :binary_path_name   => "#{rubyexe} #{SERVICE_FILE}",
      :description       => 'Run nginx, jruby all in one'
   )
  when "uninstall"  
    Service.delete(SERVICE_NAME)
  end
end

 注意:为何重载String.strip

原因在于中文版windows在安装服务过程中调用get_last_error会返回utf-8的字符,此时win32-service gem的error.rb会报invalidate byte sequence的错误。

原因是对字符串进行了strip

如果不进行strip则没有任何问题。

服务部分的代码如下:

#service.rb
require 'win32/daemon'
include Win32
SERVICE_LOG = File.expand_path(File.dirname(File.dirname(__FILE__)))+ '/services.log'
JR_PATH = 'c:\jruby-1.7.0\bin'
JR_LOG = File.expand_path(File.dirname(File.dirname(__FILE__)))+ '/jruby.log'

class Daemon

  def service_main
     while running?
        if @pid.nil?
          @pid = Process.spawn('c:\nginx-1.2.1\nginx.exe', 
            chdir: 'c:\nginx-1.2.1',
            out: SERVICE_LOG, err: :out)

          Process.detach @pid
          if @pid_jruby.nil?
            @pid_jruby = []
            start_jruby
          end
         
          Process.waitpid(@pid)
        else 
          sleep(3)
        end
     end
  end


  def service_stop
     if @pid
        pid_kill = Process.spawn('c:\nginx-1.2.1\nginx.exe -s stop', 
            chdir: 'c:\nginx-1.2.1',
            out: SERVICE_LOG, err: :out)
          Process.waitpid(pid_kill)
     end
     if @pid_jruby.size > 0 
       @pid_jruby.each do |pid| 
          pid_kill = Process.kill(9, pid)
       end
     end 
  end

  def start_jruby
    if @pid_jruby.empty?

      [3000, 4000].each do |port|
        cmd = "#{JR_PATH}\\jruby.exe -S trinidad -e production -p #{port}"
        pid =  Process.spawn(cmd, chdir: 'C:\app\', out:JR_LOG, err: :out)
        @pid_jruby << pid
        Process.detach pid
      end
    end
  end

end

Daemon.mainloop

 结果:

以上代码在ruby 1.9.3 win7 上通过

如在win7上报安装权限不足,请使用administrator 启动cmd console。

代码尚有refactory的空间,时间仓促,敬请谅解。

相关推荐