我想使用命名管道作为异步任务队列(也许类似于 JMS)。
例如,假设客户端发送了一些我希望插入到数据库中的数据,但我希望客户端立即与服务器断开连接,并且服务器进程将数据通过管道传输到命名管道中。然后完全独立地从管道读取数据并执行 SQL 插入,这可能非常慢 - 但客户端不会注意到,因为它立即得到响应。
作为原型,我认为这可行(为了简单起见,“45”是回显的,而不是通过 netcat 客户端-服务器对发送):
zsh> nohup echo "45" > my_named_pipe &
zsh> exit
zsh: warning: 1 jobs SIGHUPed
然后很久以后,执行
zsh> cat my_named_pipe
但管道里什么也没有流出来。我的设置有什么问题吗?
PS:我从来没有nohup
工作过。在这种情况下,我总是依赖于disown
我不想将其作为单独的命令来执行的操作。
答案1
当你这样做时:
nohup echo "45" > my_named_pipe &
外壳会自行分叉。对于孩子来说,它是my_named_pipe
为写作而打开的。这open()
会阻塞,直到有其他内容打开my_named_pipe
供阅读为止。
当你exit
在父进程中运行时,子进程仍然处于阻塞状态open()
,尚未执行nohup
。
因此,退出 shell 后,shell 会向子进程发送 SIGHUP 信号,它不会忽略该信号,因为它尚未运行nohup
。
赶紧跑:
(echo 45 > my_named_pipe &)
或者与zsh
:
echo 45 > my_named_pipe &!
&!
zsh 是语法糖disown
BASH 和 ZSH 都有一个很好的内置函数,称为 disown。它使用户能够以类似于 nohup 的方式从 shell 中分离进程。 ZSH 有一个很好的糖:你可以放 &!在命令结束时,它将被分离。 BASH没有这样的糖
http://blog.debiania.in.ua/posts/2013-03-13-fun-with-bash-disown.html
答案2
您遇到的问题以及它依赖于 shell 的原因是>
首先处理重定向,如果还没有人读取管道,它将阻塞。只有open成功后,shell才会执行nohup
。您在它仍处于打开状态时断开连接,因此nohup
尚未发生并且SIGHUP
杀死了后台进程。这就是为什么disown
更好。它立即适用于该工作。
从我尝试用 bash 重现问题来看,bash 似乎不会像 zsh 那样将会话结束的 SIGHUP 转发给它的子进程,因此后台作业仍然存在。