我有一个用C ++编写的旧应用程序,正在移植到Ruby。

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

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

很快就发现Ruby没有等效的execl() ,但是您可以使用Process::spawn:close_others选项部分地伪造它。 或者,至少我应该能够按照文档进行操作

文件描述符继承:是否关闭非重定向的非标准fds(3、4、5 ...):close_others => true:不继承

因此,在我看来,以下内容应该产生一个新进程,该进程可以访问父级的所有打开的文件描述符:

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父进程。 换句话说,如果我导致父级在代码末尾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调用之前(或@mata指出的Process.exec ),我有一个诊断输出:

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

同样,这是我尝试使用spawn还是exec


EDIT2给定我的诊断输出,我看到服务器与fd 7保持绑定,客户端与8保持绑定。

7 => 7,
8 => 8,

到我的options阵列,我能够使用exec在重新启动期间成功持久保留这些套接字。 对我来说,将服务器和[client1, client2,...] fd手动添加到选项哈希中是可行的,但是当:close_others应该为我做繁重的工作时,这似乎很脏。

===============>>#1 票数:0 已采纳

这当然不是我想要的解决方案,但是在没有有关:close_options Hash和Process.spawnProcess.exec的任何启示的情况下,我将所有关心的文件描述符手动添加到option s数组中,成功了:

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

我会暂时保留这个答案,以防万一有人来打破记录。

  ask by Chris Tonkinson translate from so

未解决问题?本站智能推荐:

1回复

当进程在Linux中终止时,文件描述符是否关闭?

Linux(Ubuntu)中有一个进程可以打开文件进行读取,但不会故意关闭文件。 进程终止时,操作系统会自动关闭文件描述符吗? 我的特定情况是在Rails应用程序中,我在其中打开了一个二进制文件。 我的Web服务器产生了多个Rails进程。 在每个Rails进程中从一个单例打开文件。
2回复

需要将进程ID的值动态插入命令中

我想监视由我的centos框上运行的进程打开的文件描述符的数量。 下面的命令对我有用 问题是在重新启动上述过程时需要监视它。 pid的变化,我无法获取统计信息。 好消息是pname是常量。 因此,我可以使用pgrep pname提取pid。 因此,如何以以下方式使用命令
3回复

exec,execvp,execl,execv之间的区别?

我正在编写代表Linux的新shell的代码。 我想要支持的其中一个命令是运行一个进程,例如,如果我得到以下行 command [arguments] 然后我想将command作为一个进程运行,直到它完成运行进程。 为此,我知道我需要使用fork()来获取子进程并获取它
3回复

在Ruby中执行进程时如何保留输出颜色?

我正在使用一个辅助脚本来执行rspec测试。 效果很好,除了我从rake rspec输出中丢失了所有颜色。 相应的ANSI代码似乎未包含在output字符串中。 如何执行一个过程,使其返回包含文本颜色的输出?
1回复

了解linux中execve内部的最佳方法是什么?

我尝试查看fs/exec.c的源代码(Linux内核代码)。 但是,我无法逐行了解它。 关于我应该如何形成良好理解的任何建议? 有什么资源可以说明问题吗?
3回复

使用exec在新进程中执行系统命令

我正在尝试生成一个执行系统命令的进程,而我自己的程序仍在进行,两个进程将并行运行。 我正在研究linux。 我在网上查了一下,听起来我应该使用exec()系列。 但它并不像我预期的那样有效。 例如,在下面的代码中,我只看到“之前”打印,但不是“完成”。 如果我发布任何东西,我很
1回复

使用execvp执行我在数组中拥有的命令

我有一个commands数组,我想执行这个数组中的每个命令,但是我似乎无法正常工作,所以我有 这是什么,它仅执行数组中的第一个命令,而不再执行任何操作,我将如何继续? 如果我希望命令随机执行的顺序和结果混合在一起怎么办,那么我必须使用fork吗?
2回复

终端应用程序中的exec杀死了终端

我写了一个小的ncurses工具来运行应用程序。 我要实现的是,在按Enter键并成功创建新流程之后,我想退出ncurses应用程序并关闭终端。 我用termite -e my_app (带有-e选项的每个其他终端模拟器也应该很好)运行我的应用程序。 my_app退出后,终端可能会关闭,但
1回复

在execl调用的子进程中写入管道

我不明白如何在child process sp.c中使用从mp.c创建的pipe 。 我(认为我)似乎在使用execl进行外部进程时无法访问正确的file descriptor 。 和创建的过程...
2回复

如何在Ruby命令中并行启动

我正在使用ruby编写一个终端程序,该终端程序是用C ++和Java编写的一组程序的启动程序,应在分布式系统中执行。 我想将此指令翻译成红宝石: 这是我的红宝石代码: 我虽然要创建一个线程池,然后每个线程都执行该命令。 这是合适的方法吗? 正如我研究的那样,线程无法执行