2014-04-19 90 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 

我會離開這個答案不被接受了一段時間,萬一有人走來,以正視聽。