2014-04-19 34 views
0

我有一个使用C++编写的旧应用程序,我正在将它移植到Ruby中。如何在Ruby中模仿execl()

代码的一部分使用execl(),以便在维护打开的文件描述符(此应用程序是网络服务)的同时用自身的[n更新]副本替换进程。

if (execl("./my-app", "-restart", fd.c_str(), NULL) < 0) { 

没多久弄清楚,Ruby没有execl()相当,但你可以伪造它使用Process::spawn:close_others选项的一部分。或者,至少我应该能够根据documentation

文件描述符继承:关闭非重定向非标准FDS(3,4,5,...)或不 :close_others =>真:不继承

所以,在我看来,以下应该酿出具有访问父的所有打开的文件描述符的新工艺:

server_fd = @server.to_i 
env = { 
    "APP_REBOOT" => "true", 
    "APP_SERVER_FD" => server_fd.to_s, 
} 
command = "ruby my-app.rb" 
options = { 
    :in   => :in, 
    :out   => :out, 
    :err   => :err, 
    :close_others => false, 
} 
pid = Process.spawn env, command, options 
Process.detach pid 

,这将使孩子访问描述符... ho wever我不知道如何exit父进程没有关闭所有的描述符。换句话说,如果我引起家长exit的代码的末尾:

server_fd = @server.to_i 
env = { 
    "APP_REBOOT" => "true", 
    "APP_SERVER_FD" => server_fd.to_s, 
} 
command = "ruby my-app.rb" 
options = { 
    :in   => :in, 
    :out   => :out, 
    :err   => :err, 
    :close_others => false, 
} 
pid = Process.spawn env, command, options 
Process.detach pid 
exit # ADDED THIS LINE 

然后描述符也被关闭了的孩子。

我有一种感觉,这是我的过程管理方法比Ruby特有的更多的问题,但我没有看到我做错了什么。


$ ruby -v 
ruby 2.1.0p0 (2013-12-25 revision 44422) [x86_64-linux] 

EDIT1 就在我的呼吁Process.spawn(或Process.exec作为@mata指出)我有一个诊断输出:

system 'lsof -c ruby' 

而另一个呼叫到就在我的recover_from_reboot方法里面。这是输出预重启的尾巴,你可以看到最后两行监听服务器端口和连接的客户端:

ruby 8957 chris 0u CHR 136,1  0t0  4 /dev/pts/1 
ruby 8957 chris 1u CHR 136,1  0t0  4 /dev/pts/1 
ruby 8957 chris 2u CHR 136,1  0t0  4 /dev/pts/1 
ruby 8957 chris 3r FIFO  0,8  0t0 12213372 pipe 
ruby 8957 chris 4w FIFO  0,8  0t0 12213372 pipe 
ruby 8957 chris 5r FIFO  0,8  0t0 12213373 pipe 
ruby 8957 chris 6w FIFO  0,8  0t0 12213373 pipe 
ruby 8957 chris 7u IPv4 12213374  0t0  TCP localhost.localdomain:boks-servc (LISTEN) 
ruby 8957 chris 8u IPv4 12213423  0t0  TCP localhost.localdomain:boks-servc->localhost.localdomain:45249 (ESTABLISHED) 

这是我看到后重启:

ruby 8957 chris 3r FIFO 0,8  0t0 12203947 pipe 
ruby 8957 chris 4w FIFO 0,8  0t0 12203947 pipe 
ruby 8957 chris 5r FIFO 0,8  0t0 12203948 pipe 
ruby 8957 chris 6w FIFO 0,8  0t0 12203948 pipe 

再次,这是我是否尝试spawnexec


EDIT2 鉴于我的诊断输出,我看到了从服务器不断结合的fd 7,和客户端8。通过添加

7 => 7, 
8 => 8, 

options阵列,我能够使用exec坚持成功在重新引导这些插座。我可以手动添加服务器和[client1, client2,...]fd s到选项散列,但这看起来很脏,当:close_others应该为我做繁重的工作。

+1

为什么不只是使用['exec'](http://ruby-doc.org/core-2.1.1/Process.html#method-c-exec)?它可以完成'execl'在C中所做的一切... – mata

+0

好的电话@mata,不幸的是我仍然看到相同的结果。 –

回答

0

这当然不是我一直在寻找解决方案,但在不存在有关:close_options Hash和Process.spawnProcess.exec任何启示的,我卷绕手动添加所有文件描述符我关心到option列数组,其中的伎俩:

server_fd = self.server.to_i 
client_fds = self.clients.map { |c| c.get_fd } 
env = { 
    "APP_REBOOT"  => "true", 
    "APP_SERVER_FD" => server_fd.to_s, 
    "APP_CLIENT_FDS" => Marshal.dump(client_fds), 
} 
options = { 
    :in   => :in, 
    :out   => :out, 
    :err   => :err, 
    :close_others => false, 
} 
# Add the server socket to the options Hash. 
options[server_fd] = server_fd 
# Add all the client sockets to the options Hash. 
@clients.each { |c| options[c.get_fd] = c.get_fd } 
# Begin anew. 
Process.exec env, App.binary.to_s, options 

我会离开这个答案不被接受了一段时间,万一有人走来,以正视听。