2

I want to use named pipes as asynchrnonous task queues (JMS-like, perhaps).

For example, suppose a client sends some data that I wish to insert into a database, but I want the client to disconnect from the server immediately and the server process pipe the data into a named pipe. Then completely independently read the data from the pipe and perform a SQL insert, which might be very slow - but the client doesn't notice because it gets a response immediately.

As a prototype, I thought this would work (for simplicity the "45" is echoed rather than sent through a netcat client-server pair):

zsh> nohup echo "45" > my_named_pipe &
zsh> exit
zsh: warning: 1 jobs SIGHUPed

Then much later, execute

zsh> cat my_named_pipe

But nothing comes out of the pipe. What's wrong with my setup?

PS: I've never got nohup to work. I always rely on disown which I don't want to do as a separate command in this scenario.

  • I can't reproduce this. What version of bash do you have? – user41515 Nov 20 '14 at 21:17
  • I'm actually using zsh 5.0.2 (though I wrote "bash" above). What happens when you do it? What version of bash do you use? If it works for you I should try that out myself. – Sridhar Sarnobat Nov 20 '14 at 21:46
  • Oh, it works for me with bash. So zsh is to blame? – Sridhar Sarnobat Nov 20 '14 at 21:57
  • I'd say bash is to blame for not cleaning up its children when it gets a SIGHUP but if you want to look at it another way I can't stop you – user41515 Nov 20 '14 at 22:00
4

When you do:

nohup echo "45" > my_named_pipe &

The shell forks itself. In the child, it opens my_named_pipe for writing. That open() blocks until something else opens my_named_pipe for reading.

When you run exit in the parent process, the child is still blocked on the open() and has not executed nohup yet.

So upon exiting you shell, the shell sends SIGHUP to the child, which it doesn't ignore since it has not run nohup yet.

Just run:

(echo 45 > my_named_pipe &)

Or with zsh:

echo 45 > my_named_pipe &!

&! is zsh syntactic sugar for disown

Both BASH and ZSH have a nice builtin called disown. It enables user to detach process from the shell in a way much similar to that of nohup. ZSH has a nice sugar for it: you can put &! at the end of the command, and it would be detached. BASH doesn’t have such sugar

http://blog.debiania.in.ua/posts/2013-03-13-fun-with-bash-disown.html

  • Good information. But the zsh one doesn't work. Is this a drop-in replacement for my command? Or do I need to do something else differently? – Sridhar Sarnobat Nov 20 '14 at 22:24
  • Ooops, ignore that last post. It works. Thank you :) – Sridhar Sarnobat Nov 20 '14 at 22:31
  • Is the <> redirect that you mention here not also applicable here? – mikeserv Nov 21 '14 at 1:15
2

The problem you're having, and the reason it's shell-dependent, is that the > redirection is processed first, and if nobody is reading the pipe yet, it will block. Only after the open succeeds will the shell execute nohup. You disconnected while it was still blocked in open, so nohup hadn't happened yet and the SIGHUP killed the background process. This is why disown is better. It applies to the job immediately.

From my attempt at reproducing the problem with bash, it seems that bash doesn't relay the session-ending SIGHUP to its children like zsh does, so the background job survives.

  • Thanks for the info. Good to know disown is a good solution. Is there any way to use disown "inline" like nohup? Looking at the manpages it doesn't appear so :( – Sridhar Sarnobat Nov 20 '14 at 22:28
  • Answer to my own followup question: &! – Sridhar Sarnobat Nov 20 '14 at 22:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.