Jacob MaineJacob Maine
SF Standup 3/1/2010: JRuby skips ensure blocks when killed
edit Posted by Jacob Maine on Monday March 01, 2010 at 09:18AM

When you kill a JRuby process (e.g. with a SIGINT) you can't bank on ensure blocks being executed. Of course, this is worrisome - file handles and other connections won't be closed. The problem boils down to this example:

$ cat kill_me.rb 
begin
  sleep
ensure
  puts 'executed ensure'
end
$ 
$ ruby -v
ruby 1.8.6 (2008-08-11 patchlevel 287) [universal-darwin9.0]
$
$ ruby kill_me.rb 
^Cexecuted ensure
kill_me.rb:2:in `sleep': Interrupt
    from kill_me.rb:2
$
$ jruby -v
jruby 1.4.0 (ruby 1.8.7 patchlevel 174) (2009-11-02 69fbfa3) (Java HotSpot(TM) 64-Bit Server VM 1.6.0_13) [x86_64-java]
$
$ jruby kill_me.rb 
^C$ 

Comments

  1. Mike Perham Mike Perham on March 01, 2010 at 12:16PM

    File handles and descriptors are associated with the process. The OS will clean them up when the process dies.

  2. Abhi Hiremagalur Abhi Hiremagalur on March 01, 2010 at 01:54PM

    @Mike In the specific case that led us to this issue we were trying to ensure a connection to a JMS queue is closed gracefully; unfortunately this isn't something the OS does when the JRuby process dies.

  3. Mike Perham Mike Perham on March 02, 2010 at 10:43AM

    When the process dies, the OS should close the socket and the JMS process on the other machine get notified of the socket closure. That's the whole point of TCP (the infamous 'remote server closed socket unexpectedly' error). Now of course your JMS server might misbehave in this case...

  4. Jacob Maine Jacob Maine on March 03, 2010 at 01:54PM

    For a more detailed discussion, check out the JRuby dev mailing list.

    @Mike Good point - things get cleaned up eventually, although not very gracefully. But there are a lot of scenarios where app code would want to tidy up after itself (delete files, etc.) that would be skipped if it were in the rescue/ensure blocks. In this case, we're trying to be polite to the JMS server which, as you suggested, complains when we drop connections abruptly. Fortunately, there are work-arounds (register finalizers and/or write our own signal trapping).

    As we've researched, we've decided that it's an expectations problem. As a Ruby programmer, I expect signals to raise Ruby exceptions, and trigger ensure blocks. But Java programmers have different expectations. So, it depends on whether you focus on the J(VM) part or Ruby part of JRuby.