Rails 求教,学习 EventMachine 时遇到的问题

kehao · 2012年02月21日 · 最后由 clc3123 回复于 2012年02月21日 · 5167 次阅读
EM.epoll

EM.run do

  trap("TERM") { stop(config['pid']) }
  trap("INT")  { stop(config['pid']) }

  Router.config(config)
  Router.log.info "Starting VCAP Router (#{Router.version})"
  Router.log.info "Listening on: #{inet}:#{port}" if inet && port

  Router.inet = inet || VCAP.local_ip(config['local_route'])
  Router.port = port

  # If the sock paramater is set, this will override the inet/port
  # for unix domain sockets
  if fn = config['sock']
    File.unlink(fn) if File.exists?(fn)
    Router.log.info "Listening on unix domain socket: '#{fn}'"
  end

  # Hack for running on BVTs on Macs which default to 256 FDs per process
  if RUBY_PLATFORM =~ /darwin/
    begin
      Process.setrlimit(Process::RLIMIT_NOFILE, 4096)
    rescue => e
      Router.log.info "Failed to modify the socket limit: #{e}"
    end
  end

  EM.set_descriptor_table_size(32768) # Requires Root privileges
  Router.log.info "Socket Limit:#{EM.set_descriptor_table_size}"

  create_pid_file(config['pid'])

  NATS.on_error do |e|
    if e.kind_of? NATS::ConnectError
      Router.log.error("EXITING! NATS connection failed: #{e}")
      exit!
    else
      Router.log.error("NATS problem, #{e}")
    end
  end

  EM.error_handler do |e|
    Router.log.error "Eventmachine problem, #{e}"
    Router.log.error("#{e.backtrace.join("\n")}")
  end

  begin
    # TCP/IP Socket
    Router.server = EM.start_server(inet, port, ClientConnection, false) if inet && port
    Router.local_server = EM.start_server(fn, nil, ClientConnection, true) if fn
  rescue => e
    Router.log.fatal "Problem starting server, #{e}"
    exit
  end

求教 1,EM.epoll 是什么意思?网上看了似懂非懂的

2, trap("TERM") { stop(config['pid']) } trap("INT") { stop(config['pid']) } 这是什么意思, 谢谢

这是用 EventMachine 来作事情呀,你首先就应该看 EventMachine 的文档

  1. EM 是 EventMachina 的简写,EM 跟 EventMachina 一样。EM.epoll 参见这里: http://eventmachine.rubyforge.org/docs/EPOLL.html
  2. trap("TERM") 的意思是接收来自系统的 “TERM” 信号,然后执行 block 中的代码
  3. trap("INT") 跟上面同理。

给你建议

  1. 你的主题帖子要改成 “都 EventMachine 的代码遇到的问题,求教”
  2. 你的问题需要编号,然后才能让大家针对具体编号的问题跟你讨论。

#1 楼 @lgn21st 首先感谢

第 2 个问题 kill -Signal pid signal 是发送给进程的信号,TERM(或数字 9)表示 “无条件终止” 信号 INT(或数字 2),就是 ctrl+c

#1 楼 @lgn21st 第 1 个问题,哈哈,没看懂手册上说什么,只知道 epoll 比 select,poll 好。~……~!!

#3 楼 @kehao 讲 epoll 的文档都喜欢用难懂的语言解释这个东西本身。 简单的说就是帮助你解决大并发连接的问题,比如这个: http://www.kegel.com/c10k.html

mark~ 我也不懂。

#3 楼 @kehao lz 这是拿 em 做什么应用啊?看起来很猛啊

#6 楼 @clc3123 这个是 VMware's Cloud Application Platform 的源代码,我是拉下来学习学习的 https://github.com/derekcollison/vcap

别理他,走火入魔了。

第 2 个问题 Name Num Action Description INT 2 exit KILL 9 exit cannot be blocked TERM 15 exit USR1 exit USR2 exit

9) SIGKILL 用来立即结束程序的运行. 本信号不能被阻塞, 处理和忽略. 15) SIGTERM 程序结束 (terminate) 信号, 与 SIGKILL 不同的是该信号可以被阻塞和 处理. 通常用来要求程序自己正常退出. shell 命令 kill 缺省产生这个信号. 12) SIGUSR2 留给用户使用

require 'eventmachine'  

module EchoServer  
  def post_init  
    puts "-- init"  
  end  

  def receive_data data  
    send_data "-- you sent: #{data}"  
    close_connection if data =~ /quit/i  
  end  

  def unbind  
    puts "-- disconnected"  
  end  
end  

EventMachine::run {  
  trap("TERM") { puts "==>TERM" }
  trap("USR2") { puts "==>USR2" }
  trap("KILL") { puts "==>KILL" }
  trap("INT")  { puts "==>INT"}
  EventMachine::start_server "127.0.0.1", 8081, EchoServer  
} 

kill -USR2 13059 ==>USR2

#9 楼 @calebx 感谢纠正 想起 unicorn 的重启好像用的 run "kill -USR2 `cat #{deploy_to}/current/tmp/pids/unicorn.pid`" 看了下 unicorn 源码:


lib/unicorn/http_server.rb
case SIG_QUEUE.shift
      when :QUIT # graceful shutdown
        break
      when :TERM, :INT # immediate shutdown
        stop(false)
        break
      when :USR1 # rotate logs
        logger.info "master reopening logs..."
        Unicorn::Util.reopen_logs
        logger.info "master done reopening logs"
        kill_each_worker(:USR1)
      when :USR2 # exec binary, stay alive in case something went wrong
        reexec
#.....
end

def reexec
#....
 self.reexec_pid = fork do
      listener_fds = Hash[LISTENERS.map do |sock|
        # IO#close_on_exec= will be available on any future version of
        # Ruby that sets FD_CLOEXEC by default on new file descriptors
        # ref: http://redmine.ruby-lang.org/issues/5041
        sock.close_on_exec = false if sock.respond_to?(:close_on_exec=)
        [ sock.fileno, sock ]
      end]
      ENV['UNICORN_FD'] = listener_fds.keys.join(',')
      Dir.chdir(START_CTX[:cwd])
      cmd = [ START_CTX[0] ].concat(START_CTX[:argv])

      # avoid leaking FDs we don't know about, but let before_exec
      # unset FD_CLOEXEC, if anything else in the app eventually
      # relies on FD inheritence.
      (3..1024).each do |io|
        next if listener_fds.include?(io)
        io = IO.for_fd(io) rescue next
        IO_PURGATORY << io
        io.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
      end

      # exec(command, hash) works in at least 1.9.1+, but will only be
      # required in 1.9.4/2.0.0 at earliest.
      cmd << listener_fds if RUBY_VERSION >= "1.9.1"
      logger.info "executing #{cmd.inspect} (in #{Dir.pwd})"
      before_exec.call(self)
      exec(*cmd)
    end
    proc_name 'master (old)'
#...
end

before_fork do |server, worker|
  old_pid = "#{Rails.root}/tmp/pids/unicorn.pid.oldbin"
  if File.exists?(old_pid) && server.pid != old_pid
    begin
      Process.kill("QUIT", File.read(old_pid).to_i)
    rescue Errno::ENOENT, Errno::ESRCH
      puts "Send 'QUIT' signal to unicorn error!"
    end
  end
end

#7 楼 @kehao 多谢,开眼界了

sqsy 整理学习 EventMachine 的一些文章和帖子 中提及了此贴 09月08日 17:05
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册