金字塔、叉子、Java 和插座
Pyramid, fork, Java and sockets
情况复杂:
金字塔应用程序有时需要 start/restart 一些 Java 进程(例如 Jetty)(例如接收 Jetty 的新 WAR 文件等) .
在 Pyramid 进程 (pserve
) 退出后或 Pyramid 重启之间,Jetty 进程有望继续工作。
Jetty 进程是通过 subprocess.Popen
+ shell 脚本启动的。当然,作为子进程,它继承了文件描述符,包括套接字。
现在如果 Pyramid 需要在 Jetty 仍然 运行 时重启,它不能这样做,因为子 Jetty 进程仍然有绑定到 Pyramid 的主 address/port 的套接字。
目前的解决方案:
要重新启动 Java/Jetty,请执行 fork
在子进程中关闭每个文件描述符 > 3 和 < resource.RLIMIT_NOFILE
。
在 starting/restarting Jetty 之后的子进程中执行 sys.exit
。
很好,对吧?
没有
这很复杂而且很笨拙。有没有更简单的方法来避免这个 "child process inheriting sockets" 问题?
此外,我有服务(如 APScheduler
等)运行,这需要精心关闭所有 运行 服务(当然在子进程中),否则它们会引发sys.exit
.
的例外情况
Is there a simpler way of avoiding this "child process inheriting sockets" problem?
是的,只需将 close_fds=True
传递给 Popen
构造函数或包装函数。这将关闭除 0、1 和 2 之外的所有 fds。*
如果您需要保留一些不同的集合而不是 0、1 和 2,请使用 pass_fds=[0, 2, special_file.fileno()]
而不是 close_fds=True
。但希望你不需要那个。**
* 我假设您不关心 Windows 可移植性 — 毕竟,您已经在使用 os.fork
。如果我错了,close_fds=True
将无法在具有重定向 stdio 句柄的 non-POSIX 系统上工作,因此如果您需要两者,则需要更复杂的解决方案。
** 如果您这样做:pass_fds
需要 3.2+,或 3.2+ subprocess
模块的反向移植。我很确定你没有 3.2+,因为如果你有,close_fds=True
将已经是 POSIX 系统上的默认行为,你一开始就不会遇到这个问题。 Web 服务需要它的一个常见原因是当您没有绑定端口 80 的权限时,因此您从 suid 程序继承了一个套接字,并且需要将该套接字传递给您自己的 child.
恕我直言,您应该将流程控制与 Web 应用程序流程分离。使用像 supervisord to start/stop/restart long-running applications; this can be done over XML-RPC.
这样的过程控制系统
金字塔的创造者 Chris McDonough 也是 Supervisor 的主要作者。
情况复杂:
金字塔应用程序有时需要 start/restart 一些 Java 进程(例如 Jetty)(例如接收 Jetty 的新 WAR 文件等) .
在 Pyramid 进程 (
pserve
) 退出后或 Pyramid 重启之间,Jetty 进程有望继续工作。Jetty 进程是通过
subprocess.Popen
+ shell 脚本启动的。当然,作为子进程,它继承了文件描述符,包括套接字。现在如果 Pyramid 需要在 Jetty 仍然 运行 时重启,它不能这样做,因为子 Jetty 进程仍然有绑定到 Pyramid 的主 address/port 的套接字。
目前的解决方案:
要重新启动 Java/Jetty,请执行
fork
在子进程中关闭每个文件描述符 > 3 和 <
resource.RLIMIT_NOFILE
。在 starting/restarting Jetty 之后的子进程中执行
sys.exit
。
很好,对吧?
没有
这很复杂而且很笨拙。有没有更简单的方法来避免这个 "child process inheriting sockets" 问题?
此外,我有服务(如 APScheduler
等)运行,这需要精心关闭所有 运行 服务(当然在子进程中),否则它们会引发sys.exit
.
Is there a simpler way of avoiding this "child process inheriting sockets" problem?
是的,只需将 close_fds=True
传递给 Popen
构造函数或包装函数。这将关闭除 0、1 和 2 之外的所有 fds。*
如果您需要保留一些不同的集合而不是 0、1 和 2,请使用 pass_fds=[0, 2, special_file.fileno()]
而不是 close_fds=True
。但希望你不需要那个。**
* 我假设您不关心 Windows 可移植性 — 毕竟,您已经在使用 os.fork
。如果我错了,close_fds=True
将无法在具有重定向 stdio 句柄的 non-POSIX 系统上工作,因此如果您需要两者,则需要更复杂的解决方案。
** 如果您这样做:pass_fds
需要 3.2+,或 3.2+ subprocess
模块的反向移植。我很确定你没有 3.2+,因为如果你有,close_fds=True
将已经是 POSIX 系统上的默认行为,你一开始就不会遇到这个问题。 Web 服务需要它的一个常见原因是当您没有绑定端口 80 的权限时,因此您从 suid 程序继承了一个套接字,并且需要将该套接字传递给您自己的 child.
恕我直言,您应该将流程控制与 Web 应用程序流程分离。使用像 supervisord to start/stop/restart long-running applications; this can be done over XML-RPC.
这样的过程控制系统金字塔的创造者 Chris McDonough 也是 Supervisor 的主要作者。