Starting a process and specifying its parent

Hi,

I need to start a (sub)process from inside a ruby script that will continue
to run after the ruby script itself has finished.
The way I'm doing stuff right now is by using Process.spawn - this works,
however the ppid of the child process is assigned to the script that was
used to start the process, and thus after the script finishes the spawned
(child) processes gets closed as well.

My question is what would be the best way to start such a (sub)process and
assign it a parent in such a way that it keeps running even after the
current script has ended? As a side-note, I also need to be able to capture
the stderr and assign it to a specific file (which works using
Process.spawn), but I'm not sure about the other methods.
I have to mention I'm using a linux machine but I'm unfortunately not very
familiar with the way linux process exactly work...

Thank you,
Victor

I need to start a (sub)process from inside a ruby script that will continue
to run after the ruby script itself has finished.
The way I'm doing stuff right now is by using Process.spawn - this works,
however the ppid of the child process is assigned to the script that was
used to start the process, and thus after the script finishes the spawned
(child) processes gets closed as well.

No. Storing the PID of the child somewhere and stopping the child
process are completely unrelated:

12:54:32 ~$ ruby19 -e 'p Process.spawn("bash", "-c", "sleep 10; echo
from shell; date"); puts "from ruby #{Time.now}"'
228
from ruby 2012-02-02 12:54:41 +0100
12:54:41 ~$ from shell
Thu, Feb 02, 2012 12:54:51 PM

It must be something else which terminates the child. Do you close
the terminal?

My question is what would be the best way to start such a (sub)process and
assign it a parent in such a way that it keeps running even after the
current script has ended? As a side-note, I also need to be able to capture
the stderr and assign it to a specific file (which works using
Process.spawn), but I'm not sure about the other methods.
I have to mention I'm using a linux machine but I'm unfortunately not very
familiar with the way linux process exactly work...

You could do

fork do
  $stdin.close
  $stdout.reopen "/dev/null"
  $stderr.reopen "/tmp/errors"
  exec "your_command", "with", "arguments"
end

You'll find more by searching for "demonize".

Kind regards

robert

···

On Thu, Feb 2, 2012 at 8:29 AM, Victor Blaga <vic.blaga@gmail.com> wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

You need at least 2 forks to be certain that the final process is completely independent from any "controlling terminal".

See http://linux.about.com/library/cmd/blcmdl2_setsid.htm for a partial description of the underlying mechanism.

In Ruby, this is available from Process.setsid

From Ruby, you probably want to use Process.daemon, which uses a higher-level call that is made up of standardized (by POSIX) system calls though daemon itself is not a standard system call.

-Rob

P.S. If you want more details, you can read up here:

http://blog.samat.org/2005/06/02/the_semantics_of_a_fork_followed_by_setsid_and_another_fork
  Creating a daemon the Python way « Python recipes « ActiveState Code
   [Warning: Python code :wink: but the comments go into great detail
   on why the underlying system calls are being made

···

On Feb 2, 2012, at 2:29 AM, Victor Blaga wrote:

Hi,

I need to start a (sub)process from inside a ruby script that will continue
to run after the ruby script itself has finished.
The way I'm doing stuff right now is by using Process.spawn - this works,
however the ppid of the child process is assigned to the script that was
used to start the process, and thus after the script finishes the spawned
(child) processes gets closed as well.

My question is what would be the best way to start such a (sub)process and
assign it a parent in such a way that it keeps running even after the
current script has ended? As a side-note, I also need to be able to capture
the stderr and assign it to a specific file (which works using
Process.spawn), but I'm not sure about the other methods.
I have to mention I'm using a linux machine but I'm unfortunately not very
familiar with the way linux process exactly work...

Thank you,
Victor

Hi Robert,

Thank you for your answer. I've further investigated the issue and you are
right. I was also calling Process.detach on the pid of the child process.
When I read the documentation I falsely understood that this method would
detach the parent process from the child process, which in my opinion ment
that once the parent process finishes the child process remains. However it
seems that it has the opposite effect.

By not calling Process.detach once the parent process closes the child
process get's assigned as parentpid = 1 (which is the master process or so
I understand).

Thank you and kind regards,
Victor

···

2012/2/2 Robert Klemme <shortcutter@googlemail.com>

On Thu, Feb 2, 2012 at 8:29 AM, Victor Blaga <vic.blaga@gmail.com> wrote:
> I need to start a (sub)process from inside a ruby script that will
continue
> to run after the ruby script itself has finished.
> The way I'm doing stuff right now is by using Process.spawn - this works,
> however the ppid of the child process is assigned to the script that was
> used to start the process, and thus after the script finishes the spawned
> (child) processes gets closed as well.

No. Storing the PID of the child somewhere and stopping the child
process are completely unrelated:

12:54:32 ~$ ruby19 -e 'p Process.spawn("bash", "-c", "sleep 10; echo
from shell; date"); puts "from ruby #{Time.now}"'
228
from ruby 2012-02-02 12:54:41 +0100
12:54:41 ~$ from shell
Thu, Feb 02, 2012 12:54:51 PM

It must be something else which terminates the child. Do you close
the terminal?

> My question is what would be the best way to start such a (sub)process
and
> assign it a parent in such a way that it keeps running even after the
> current script has ended? As a side-note, I also need to be able to
capture
> the stderr and assign it to a specific file (which works using
> Process.spawn), but I'm not sure about the other methods.
> I have to mention I'm using a linux machine but I'm unfortunately not
very
> familiar with the way linux process exactly work...

You could do

fork do
$stdin.close
$stdout.reopen "/dev/null"
$stderr.reopen "/tmp/errors"
exec "your_command", "with", "arguments"
end

You'll find more by searching for "demonize".

Kind regards

robert

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Victor, please do not top post.

Thank you for your answer. I've further investigated the issue and you are
right. I was also calling Process.detach on the pid of the child process.
When I read the documentation I falsely understood that this method would
detach the parent process from the child process, which in my opinion ment
that once the parent process finishes the child process remains. However it
seems that it has the opposite effect.

Not sure what you mean by "opposite effect" here. Process.detach only
ensures that the child process does not become a zombie when it dies
before this process (the parent) by automatically reaping it (see "ri
Process.detach"). If the parent dies before the child anyway, you do
not have to do anything because then init (PID 1) will become the
parent and do the reaping.

By not calling Process.detach once the parent process closes the child
process get's assigned as parentpid = 1 (which is the master process or so
I understand).

And that will reap the child. Please read this for more information:

Kind regards

robert

···

On Thu, Feb 2, 2012 at 1:06 PM, Victor Blaga <vic.blaga@gmail.com> wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/