【发布时间】:2015-05-01 03:35:58
【问题描述】:
一个复杂的情况:
Pyramid 应用程序有时需要启动/重新启动一些 Java 进程(例如 Jetty)(例如在接收 Jetty 的新 WAR 文件等时)。
预计 Jetty 进程将在 Pyramid 进程 (
pserve) 退出后或 Pyramid 重新启动之间继续工作。Jetty 进程通过
subprocess.Popen+ shell 脚本启动。自然地,作为一个子进程,它继承了文件描述符,包括套接字。现在如果 Pyramid 需要在 Jetty 仍在运行时重新启动,它不能这样做,因为子 Jetty 进程仍然将套接字绑定到 Pyramid 的主地址/端口。
目前的解决方案:
要重新启动 Java/Jetty,请执行
fork在子进程中关闭每个文件描述符 > 3 和 resource.RLIMIT_NOFILE。
在启动/重启 Jetty 后在子进程中执行
sys.exit。
整洁,对吧?
没有。
这是复杂而笨拙的。有没有更简单的方法来避免这种“子进程继承套接字”的问题?
另外,我有服务(如 APScheduler 等)正在运行,这需要精心关闭所有正在运行的服务(当然是在子进程中),否则它们会在 sys.exit 上引发异常。
【问题讨论】:
-
我不确定这是否是您想要的,但是使用 Apache Java 服务,您可以将 Jetty 作为操作系统服务运行并启动/停止它。
-
我同意@SJuan76——您应该明确地使用更高级别的 API 来启动和停止该服务。这将以某种方式将这两个部分解耦,让“服务管理器”处理混乱的部分(启动与重新启动,重新启动异常终止的 Jetty 实例等等......)此外,它将负责正确的“身份管理”,如一个普通的旧分叉将让子进程在与父进程相同的身份(即:相同的权限)下运行。这可能是不可取的。
-
@SylvainLeroux:好吧,您可以使用
preexec_fn=lambda: os.setresuid(unprived_user)或类似名称处理子进程中的身份,而在普通的旧分叉中,只需在fork之后显式调用它,因此子代码甚至永远不会由特权用户加载。 -
@SylvainLeroux:基本上,
setresuid同时设置了所有三个真实的、有效的和保存的 uid;这只是对单独方法的方便。例如,如果您的有效 uid 为pyramid,但保存的 uid 为root,则setresuid(geteuid())会阻止孩子(ab)使用该保存的 uid。无论如何,我同意你的一般观点,我只是想提一下,做你需要的不是不可能;问题是你必须知道你需要它,以及如何测试它,等等;编写系统工具的人(希望如此)已经想到了所有这些。 :) -
他并不是建议构建一个与您的整个应用程序集成的服务管理器。只需使用您的操作系统附带的那个(upstart、systemd、launchd,……——如果您更喜欢操作系统的替代版本,您也可以安装它)。然后通过运行简单的命令行调用工具(通过
subprocess)进行通信,例如systemctl restart jetty或launchctl stop jetty或其他。重启或停止 Jetty 不需要传递活动对象,不是吗?
标签: java python sockets fork pyramid