at_exit handlers and Process.kill

D

Daniel Berger

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
 
D

Daniel Berger

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?

Thanks,

Dan
 
T

ts

Daniel said:
# 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 ?
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)

This is SIGTRAP


Guy Decoux
 
D

Daniel Berger

ts said:
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
 
D

Daniel Berger

ts said:
Try this


ruby -e 'sleep 1 while true; p :eek:k'


and wait that it give :eek:k ...

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
 
K

Ken Bloom

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

--Ken
 
T

Tim Pease

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
 
T

ts

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

at_exit and trap the signal that you want but *please* do this
*before* 'sleep 1 while true'

moulon% ruby -e 'at_exit { puts :exit}; trap("TRAP") { puts :SIGTRAP;
exit }; sleep 1 while true'
SIGTRAP
exit
moulon%


Guy Decoux
 
J

Joel VanderWerf

Ken said:
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)
 
T

Tim Pease

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,


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
 
D

Daniel Berger

Ken said:
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
 
D

Daniel Berger

Tim said:
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
 
D

Daniel Berger

Joel said:
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. :)

Many thanks,

Dan
 
K

Ken Bloom

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
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
 
G

Gennady Bystritsky

Ken said:
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
 
T

Tim Pease

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 ;)

TwP
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,186
Members
46,740
Latest member
JudsonFrie

Latest Threads

Top