1

I have written a program that can run for 16 or 20 hours on a linux box with some form of redhat OS. It runs fine if I start it up with nohup or redirect output to a file, but when a user starts it up, sends it to the background and logs out, it will fail when it tries to send a simple status message (reporting the number of files that file resulted in). It throws an exception, presumably because the stream is no longer valid.

Once we realized why it worked for me, but not for him, I ran a few tests, and discovered that ruby is unique in this behavior when compared with Python, Bash and perl.

Is there a good reason that ruby behaves differently from the other scripting languages in this situation? Is there a way to change it to behave like the rest?

I am pretty sure that C++ (and C) don't care if the end user can see the output of their messages-but I didn't write up a test for those languages. I was surprised to find out that jobs sent to the background didn't go away once you logged out! So, I certainly never tested for this behavior in the past.

user632657
  • 473
  • 3
  • 10

2 Answers2

0

If you go to background, i believe every program in any language trying to write to stdout should get error code. In case of C, you would get some return value, which you might ignore. In other languages, i would be really surprised, if really only ruby throwed exception. After all, this is how is os made, problem lies in kernel. I wrote one daemon in perl and i am sure i had to implement stdout,stderr and stdin closing and double forking to not be killed without nohup. You should not rely on undocumented features and either depend on nohup to do it for you, or properly closing input and output descriptors. Or reopen them to logfile using low-level open call.

Have you tried always with redirecting to or from your script with other languages as well? Broken pipe is error usually when program1 | program2 anonymous pipe has one of their ends closed and the other ask to read/write from it.

Pihhan
  • 813
  • 5
  • 11
  • For a few languages, we have verified that the languages do not generate an error: – user632657 Nov 14 '11 at 19:09
  • #!/bin/bash; sleep 60; echo "OK"; touch jflkdfakl #If you send this to the background and log out, the file will be created. This same behavior can be observed with python and perl as well. But Ruby raises an exception. -- it is ignoring the first four spaces... – user632657 Nov 14 '11 at 19:10
0

When you log out, the process that is the receiver of your $stderr and $stdout is killed. Your $stderr and $stdout file descriptors are now connected to a broken pipe. When you write to them, you should get SIGPIPE from the operating system.

You're wrong about C++ and C not caring. It's got nothing to do with the implementation language, or with whether or not "a user" can "see" the output. It's about whether the file descriptor is still valid. Since the other end has closed, it isn't any more.

Take a look at a daemon written in C or C++. Notice how it closes stderr and stdout in the child process, after fork and before exec. This is how it protects itself from writing to a broken pipe and being sent a SIGPIPE by the operating system.

sheldonh
  • 2,684
  • 24
  • 31
  • I just wrote a little C++ test. It behaves the same as my python script. I have it writing to std::out every 10 seconds for N times and also echoing to a file. If I send it to the background and log out, the program continues to completion with no error. Ruby would stop at the first write to std::out after the user terminated the session (though, if the process never attempted to write to std::out/err, it would continue running until completion. – user632657 Nov 14 '11 at 19:41
  • I shouldn't have mentioned C++, because I don't know it, sorry. My guess is that the IO implementation you're using in your sample program is protecting you from a write(2) on a broken pipe. – sheldonh Nov 16 '11 at 12:49
  • Daemons are a special case, and this isn't really a daemon. It's just a regular program that needs to run for hours, and our cluster does kill sessions from time to time for various reasons. So, if the session goes away, any in any language other than ruby, the program will complete without an error. But, with ruby, the lost session will throw an exception. – user632657 Nov 28 '11 at 17:07
  • I should also say that the session is killed, but not the job itself. – user632657 Nov 28 '11 at 17:08