2

My ruby script creates a tempfile and spawns an potentially long-running external process. Neither may continue to exist after the script ends, no matter the way in which the script terminates.

I thought the following lines would take care of things:

stderr = File.open(Tempfile.new(__FILE__),'w')
trap("EXIT") { FileUtils.rm_f stderr.path }
pid = spawn("dd", *ARGV, STDERR => stderr )
trap("EXIT") { FileUtils.rm_f stderr.path; Process.kill pid }

they're supposed to be a rewrite of the following bash code, which seems to work fine,

dd_output=`mktemp`
trap "rm -f $dd_output" EXIT
dd "$@" 2>| $dd_output & pid=$!
trap "rm -f $dd_output; kill $pid" EXIT

but they don't. If an exception is raised later on, the spawned process doesn't die, otherwise it does.

Could anyone tell me what I'm doing wrong?

Edit: Traps do work. The above code has multiple blemishes:

  1. Tempfile takes car of itself -- it is likely to already have been deleted in the trap handler, which may cause FileUtils.rm_f to raise another error, preventing.
  2. Process.kill needs a signal -- Process.kill "TERM", pid (or "KILL"). The raised error shadowed the error for my faulty invocation of Process.kill.

Fixed code:

 stderr = Tempfile.new(__FILE__)
 pid = spawn("dd", *ARGV, STDERR => stderr )
 trap("EXIT") { Process.kill "TERM", pid }

Ensure works too.

Jolta
  • 2,620
  • 1
  • 29
  • 42
Petr Skocik
  • 58,047
  • 6
  • 95
  • 142

1 Answers1

2

I think ensure might be able to help you here, it will always execute the code inside. It is similary to Java's finally.

stderr = Tempfile.new(__FILE__)

begin
  pid = spawn("dd", *ARGV, STDERR => stderr )
ensure
  FileUtils.rm_f stderr.path
  Process.kill pid
end

If that doesn't do the trick you could try adding an at_exit handler.

Jesus Castello
  • 1,103
  • 11
  • 20