At_exit handlers and Process.kill

Hi all,

Ruby 1.8.6 p114
OS X 10.4

None of these handlers get picked up when I kill the 'process_test.rb' program with an external program. Why not?

# process_test.rb
File.open("pid.txt", "w"){ |fh| fh.print Process.pid }
p Process.pid

sleep 1 while true

at_exit {
    puts "AT_EXIT"
}

END{
    puts "END"
}

trap("KILL"){
    puts "KILLED"
}

# kill_test.rb
pid = IO.read("pid.txt").to_i
p pid
Process.kill(5, pid)

Dan

Daniel Berger wrote:

Hi all,

Ruby 1.8.6 p114
OS X 10.4

None of these handlers get picked up when I kill the 'process_test.rb' program with an external program. Why not?

I had to use all of them:

Signal.trap("KILL") { }
Signal.trap("EXIT") { }
Signal.trap("TERM") { }
Signal.trap("ABRT") { }

Use Signal.list to get a list of available signals to trap on you machine.

···

--
Oinopion

ts wrote:

Daniel Berger wrote:

# process_test.rb
File.open("pid.txt", "w"){ |fh| fh.print Process.pid }
p Process.pid

sleep 1 while true

you really think that the following line will be executed ?

Why not? The docs say at_exit, "Converts block to a Proc object (and therefore binds it at the point of call), and registers
it for execution when the program exits."

Well, the program exited, didn't it?

If this just can't work then I think there needs to be a way to handle graceful cleanup without having to trap all the possible signals that could kill the program.

Regards,

Dan

This works for me on OS 10.5.2 and ruby-1.8.6-p111

$ cat runner.rb
File.open('pid.txt', 'w') {|fd| fd.puts Process.pid}
puts Process.pid

at_exit {$stderr.puts "AT_EXIT"}
END {$stderr.puts "END"}
Signal.trap(5) {$stderr.puts "KILLED"}

loop {sleep 1}

$ cat killer.rb
pid = Integer(File.read('pid.txt'))
puts pid

Process.kill(5,pid)

And when I run the killer script the runner script dies and outputs "KILLED" to stderr.

The only real difference was using the explicit signal number (5) and putting the infinite sleep after all the exit handlers were registered. The only handler that was run was the block handling the trap. But the END block and the at_exit block were not run. I would expect that since a sigkill is pretty severe.

Blessings,
TwP

···

On Apr 15, 2008, at 6:58 AM, Daniel Berger wrote:

Hi all,

Ruby 1.8.6 p114
OS X 10.4

None of these handlers get picked up when I kill the 'process_test.rb' program with an external program. Why not?

# process_test.rb
File.open("pid.txt", "w"){ |fh| fh.print Process.pid }
p Process.pid

sleep 1 while true

at_exit {
  puts "AT_EXIT"
}

END{
  puts "END"
}

trap("KILL"){
  puts "KILLED"
}

# kill_test.rb
pid = IO.read("pid.txt").to_i
p pid
Process.kill(5, pid)

Dan

Ok, what about the at_exit handler?

Thanks,

Dan

···

On Apr 15, 7:25 am, Tomek Paczkowski <oinop...@gmail.com> wrote:

Daniel Berger wrote:
> Hi all,

> Ruby 1.8.6 p114
> OS X 10.4

> None of these handlers get picked up when I kill the 'process_test.rb'
> program with an external program. Why not?

I had to use all of them:

Signal.trap("KILL") { }
Signal.trap("EXIT") { }
Signal.trap("TERM") { }
Signal.trap("ABRT") { }

Use Signal.list to get a list of available signals to trap on you machine.

ts wrote:

Daniel Berger wrote:

sleep 1 while true

you really think that the following line will be executed ?

Why not?

Try this

ruby -e 'sleep 1 while true; p :ok'

and wait that it give :ok ...

Yes, Guy, I understand that. You aren't listening.

How do I create an all purpose cleanup handler within a Ruby program that will fire off no matter how the script is terminated?

Thanks,

Dan

Ruby does *everything* in the order it encounters it in the file.
at_exit installs an exit handler, (a proc to be run later) but it's a
method that has to be executed. If you put "sleep 1 while true" before
the at_exit call, the at_exit call will never be executed, so the exit
handler will never be installed. Adjust your program to call at_exit (or
whatever other handlers you want) before running anything else.

# process_test.rb
at_exit {
    puts "AT_EXIT"
}

END{
    puts "END"
}

trap("KILL"){
    puts "KILLED"
}

File.open("pid.txt", "w"){ |fh| fh.print Process.pid }
p Process.pid

sleep 1 while true

--Ken

···

On Tue, 15 Apr 2008 11:28:33 -0500, Daniel Berger wrote:

ts wrote:

Daniel Berger wrote:

# process_test.rb
File.open("pid.txt", "w"){ |fh| fh.print Process.pid } p Process.pid

sleep 1 while true

you really think that the following line will be executed ?

Why not? The docs say at_exit, "Converts block to a Proc object (and
therefore binds it at the point of call), and registers it for execution
when the program exits."

--
Ken (Chanoch) Bloom. PhD candidate. Linguistic Cognition Laboratory.
Department of Computer Science. Illinois Institute of Technology.
http://www.iit.edu/~kbloom1/

Tim Pease wrote:

Hi all,

Ruby 1.8.6 p114
OS X 10.4

None of these handlers get picked up when I kill the 'process_test.rb' program with an external program. Why not?

# process_test.rb
File.open("pid.txt", "w"){ |fh| fh.print Process.pid }
p Process.pid

sleep 1 while true

at_exit {
  puts "AT_EXIT"
}

END{
  puts "END"
}

trap("KILL"){
  puts "KILLED"
}

# kill_test.rb
pid = IO.read("pid.txt").to_i
p pid
Process.kill(5, pid)

Dan

This works for me on OS 10.5.2 and ruby-1.8.6-p111

$ cat runner.rb
File.open('pid.txt', 'w') {|fd| fd.puts Process.pid}
puts Process.pid

at_exit {$stderr.puts "AT_EXIT"}
END {$stderr.puts "END"}
Signal.trap(5) {$stderr.puts "KILLED"}

loop {sleep 1}

$ cat killer.rb
pid = Integer(File.read('pid.txt'))
puts pid

Process.kill(5,pid)

And when I run the killer script the runner script dies and outputs "KILLED" to stderr.

The only real difference was using the explicit signal number (5) and putting the infinite sleep after all the exit handlers were registered. The only handler that was run was the block handling the trap. But the END block and the at_exit block were not run. I would expect that since a sigkill is pretty severe.

Blessings,
TwP

Were you able to get at_exit or END to fire off with other signals?

Thanks,

Dan

···

On Apr 15, 2008, at 6:58 AM, Daniel Berger wrote:

It will work if you put things in the right order. (See my other answer.)

--Ken

···

On Tue, 15 Apr 2008 08:35:35 -0500, Daniel Berger wrote:

On Apr 15, 7:25 am, Tomek Paczkowski <oinop...@gmail.com> wrote:

Daniel Berger wrote:
> Hi all,

> Ruby 1.8.6 p114
> OS X 10.4

> None of these handlers get picked up when I kill the
> 'process_test.rb' program with an external program. Why not?

I had to use all of them:

Signal.trap("KILL") { }
Signal.trap("EXIT") { }
Signal.trap("TERM") { }
Signal.trap("ABRT") { }

Use Signal.list to get a list of available signals to trap on you
machine.

Ok, what about the at_exit handler?

--
Ken (Chanoch) Bloom. PhD candidate. Linguistic Cognition Laboratory.
Department of Computer Science. Illinois Institute of Technology.
http://www.iit.edu/~kbloom1/

Ken Bloom wrote:

ts wrote:

Daniel Berger wrote:

# process_test.rb
File.open("pid.txt", "w"){ |fh| fh.print Process.pid } p Process.pid

sleep 1 while true

you really think that the following line will be executed ?

Why not? The docs say at_exit, "Converts block to a Proc object (and
therefore binds it at the point of call), and registers it for execution
when the program exits."

Ruby does *everything* in the order it encounters it in the file.
at_exit installs an exit handler, (a proc to be run later) but it's a method that has to be executed. If you put "sleep 1 while true" before the at_exit call, the at_exit call will never be executed, so the exit handler will never be installed. Adjust your program to call at_exit (or whatever other handlers you want) before running anything else.

Note that you can use BEGIN to register handlers out of order:

exit

BEGIN {
   at_exit { puts "at_exit" }
   END { puts "END" }
}

(without the BEGIN, nothing is printed)

···

On Tue, 15 Apr 2008 11:28:33 -0500, Daniel Berger wrote:

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

cleanup = lambda {
   next if $cleanup_was_already_done
   $cleanup_was_already_done = true
   # your cleanup code goes here
}

Signal.list.values.each do |signal|
   Signal.trap(signal,&cleanup)
end

at_exit &cleanup

Blessings,
TwP

···

On Apr 15, 2008, at 10:58 AM, Daniel Berger wrote:

Yes, Guy, I understand that. You aren't listening.

How do I create an all purpose cleanup handler within a Ruby program that will fire off no matter how the script is terminated?

Thanks,

Ken Bloom wrote:

···

On Tue, 15 Apr 2008 11:28:33 -0500, Daniel Berger wrote:

ts wrote:

Daniel Berger wrote:

# process_test.rb
File.open("pid.txt", "w"){ |fh| fh.print Process.pid } p Process.pid

sleep 1 while true

you really think that the following line will be executed ?

Why not? The docs say at_exit, "Converts block to a Proc object (and
therefore binds it at the point of call), and registers it for execution
when the program exits."

Ruby does *everything* in the order it encounters it in the file.
at_exit installs an exit handler, (a proc to be run later) but it's a method that has to be executed. If you put "sleep 1 while true" before the at_exit call, the at_exit call will never be executed, so the exit handler will never be installed. Adjust your program to call at_exit (or whatever other handlers you want) before running anything else.

# process_test.rb
at_exit {
    puts "AT_EXIT"
}

END{
    puts "END"
}

trap("KILL"){
    puts "KILLED"
}

File.open("pid.txt", "w"){ |fh| fh.print Process.pid }
p Process.pid

sleep 1 while true

Right, I should have clarified that, even with the right ordering, at_exit and END blocks weren't called.

Perhaps it's the signal I used? I haven't fully experimented yet...

Regards,

Dan

Joel VanderWerf wrote:

Ken Bloom wrote:

ts wrote:

Daniel Berger wrote:

# process_test.rb
File.open("pid.txt", "w"){ |fh| fh.print Process.pid } p Process.pid

sleep 1 while true

you really think that the following line will be executed ?

Why not? The docs say at_exit, "Converts block to a Proc object (and
therefore binds it at the point of call), and registers it for execution
when the program exits."

Ruby does *everything* in the order it encounters it in the file.
at_exit installs an exit handler, (a proc to be run later) but it's a method that has to be executed. If you put "sleep 1 while true" before the at_exit call, the at_exit call will never be executed, so the exit handler will never be installed. Adjust your program to call at_exit (or whatever other handlers you want) before running anything else.

Note that you can use BEGIN to register handlers out of order:

exit

BEGIN {
  at_exit { puts "at_exit" }
  END { puts "END" }
}

(without the BEGIN, nothing is printed)

Ah, yes. I think between this and Tim's all purpose catcher, we have the makings of a nice little library. :slight_smile:

Many thanks,

Dan

···

On Tue, 15 Apr 2008 11:28:33 -0500, Daniel Berger wrote:

See signal(7) for descriptions and numbers of the various signals. Most
likely you want to use SIGINT (signal 1), and then at_exit will be
sufficient. Note that SIGKILL (signal 9) cannot be caught under any
circumstances (it's used to kill badly misbehaving applications), so your
sigkill handler is useless.

I think it's unnecessary to install lots of signal handlers to do the
cleanup. Just learn what each signal does, and what to expect, and
at_exit should already be designed to do what you want.

--Ken

···

On Tue, 15 Apr 2008 12:29:01 -0500, Daniel Berger wrote:

Ken Bloom wrote:

On Tue, 15 Apr 2008 11:28:33 -0500, Daniel Berger wrote:

ts wrote:

Daniel Berger wrote:

# process_test.rb
File.open("pid.txt", "w"){ |fh| fh.print Process.pid } p Process.pid

sleep 1 while true

you really think that the following line will be executed ?

Why not? The docs say at_exit, "Converts block to a Proc object (and
therefore binds it at the point of call), and registers it for
execution when the program exits."

Ruby does *everything* in the order it encounters it in the file.
at_exit installs an exit handler, (a proc to be run later) but it's a
method that has to be executed. If you put "sleep 1 while true" before
the at_exit call, the at_exit call will never be executed, so the exit
handler will never be installed. Adjust your program to call at_exit
(or whatever other handlers you want) before running anything else.

# process_test.rb
at_exit {
    puts "AT_EXIT"
}

END{
    puts "END"
}

trap("KILL"){
    puts "KILLED"
}

File.open("pid.txt", "w"){ |fh| fh.print Process.pid } p Process.pid

sleep 1 while true

Right, I should have clarified that, even with the right ordering,
at_exit and END blocks weren't called.

Perhaps it's the signal I used? I haven't fully experimented yet...

Regards,

Dan

--
Ken (Chanoch) Bloom. PhD candidate. Linguistic Cognition Laboratory.
Department of Computer Science. Illinois Institute of Technology.
http://www.iit.edu/~kbloom1/

only -9 works in windows

a @ http://codeforpeople.com/

···

On Apr 15, 2008, at 11:29 AM, Daniel Berger wrote:

Perhaps it's the signal I used? I haven't fully experimented yet...

--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama

cleanup = lambda do
   cleanup = lambda{}
   p 'cleanup'
end

a @ http://codeforpeople.com/

···

On Apr 15, 2008, at 11:25 AM, Tim Pease wrote:

cleanup = lambda {
next if $cleanup_was_already_done
$cleanup_was_already_done = true
# your cleanup code goes here
}

Signal.list.values.each do |signal|
Signal.trap(signal,&cleanup)
end

--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama

Ken Bloom wrote:

Ken Bloom wrote:

ts wrote:

Daniel Berger wrote:

# process_test.rb
File.open("pid.txt", "w"){ |fh| fh.print Process.pid } p
Process.pid

sleep 1 while true

you really think that the following line will be executed ?

Why not? The docs say at_exit, "Converts block to a Proc object
(and therefore binds it at the point of call), and registers it for
execution when the program exits."

Ruby does *everything* in the order it encounters it in the file.
at_exit installs an exit handler, (a proc to be run later) but it's
a method that has to be executed. If you put "sleep 1 while true"
before the at_exit call, the at_exit call will never be executed,
so the exit handler will never be installed. Adjust your program to
call at_exit (or whatever other handlers you want) before running
anything else.

# process_test.rb
at_exit {
    puts "AT_EXIT"
}

END{
    puts "END"
}

trap("KILL"){
    puts "KILLED"
}

File.open("pid.txt", "w"){ |fh| fh.print Process.pid } p Process.pid

sleep 1 while true

Right, I should have clarified that, even with the right ordering,
at_exit and END blocks weren't called.

Perhaps it's the signal I used? I haven't fully experimented yet...

Regards,

Dan

See signal(7) for descriptions and numbers of the various
signals. Most
likely you want to use SIGINT (signal 1), and then at_exit will be

SIGINT is 2, 1 is SIGHUP

···

On Tue, 15 Apr 2008 12:29:01 -0500, Daniel Berger wrote:

On Tue, 15 Apr 2008 11:28:33 -0500, Daniel Berger wrote:

sufficient. Note that SIGKILL (signal 9) cannot be caught under any
circumstances (it's used to kill badly misbehaving
applications), so your
sigkill handler is useless.

I think it's unnecessary to install lots of signal handlers to do the
cleanup. Just learn what each signal does, and what to expect, and
at_exit should already be designed to do what you want.

--Ken

That's not going to work. The various exit handlers already have a reference to the cleanup proc, so reassigning the cleanup variable will not prevent it from getting called twice. I know that global variables are ugly, but there is a time and a place for everything.

And it's way too clever for me :wink:

TwP

···

On Apr 15, 2008, at 7:10 PM, ara.t.howard wrote:

On Apr 15, 2008, at 11:25 AM, Tim Pease wrote:

cleanup = lambda {
next if $cleanup_was_already_done
$cleanup_was_already_done = true
# your cleanup code goes here
}

Signal.list.values.each do |signal|
Signal.trap(signal,&cleanup)
end

cleanup = lambda do
cleanup = lambda{}
p 'cleanup'
end

the whole code:

cfp:~ > cat a.rb
cleanup = lambda do
   cleanup = lambda{}
   p :cleanup
end

Signal.trap('HUP'){ cleanup.call }
Signal.trap('USR1'){ cleanup.call }

Process.kill 'HUP', Process.pid
Process.kill 'USR1', Process.pid

cfp:~ > ruby a.rb
:cleanup

just avoids needing an external/global switch...

a @ http://codeforpeople.com/

···

On Apr 16, 2008, at 8:51 AM, Tim Pease wrote:

cleanup = lambda {
next if $cleanup_was_already_done
$cleanup_was_already_done = true
# your cleanup code goes here
}

Signal.list.values.each do |signal|
Signal.trap(signal,&cleanup)
end

cleanup = lambda do
cleanup = lambda{}
p 'cleanup'
end

That's not going to work. The various exit handlers already have a reference to the cleanup proc, so reassigning the cleanup variable will not prevent it from getting called twice. I know that global variables are ugly, but there is a time and a place for everything.

And it's way too clever for me :wink:

--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama