Hijack: Get A Live IRB Prompt For Any Existing Ruby Process
Sometimes taking an app down for debugging purposes is just not an option. Luckily a new tool called Hijack can provide a live IRB prompt for an existing Ruby process in the same way that Erlang provides hot swapping of code (changing the definition of a system while the system is still up and running).
Hijack (it's still in a beta state, so be careful and don't use it in production yet!) lets you to pry your way into a running Ruby process, where it drops you into a live IRB session running over DRB. Gone are the days of stopping live applications just to make a minor update!
Using the GDB (GNU DeBugger), Hijack connects to the running Ruby process, injecting a small payload to start a DRB session which provides an IRB session:
$ ruby hijack 16451 => Hijacking... => Mirroring: 100% => Hijacked 16451 (my_script.rb) (ruby 1.8.7 [i686-darwin9]) >>
You may already be familiar with live-console which provides a similar functionality. The key difference, however, is that Hijack can "inject" itself into an existing Ruby process without needing the code to have included it explicitly. Developer Ian Leitch explains:
I've just changed Hijack so that you can hijack any Ruby process - no need for your target process to require any code before it can be hijacked. It does this by first injecting a payload using gdb, then it signals the process to start up a DRb server which the hijack client then connects to.
Jumpstart Lab is running a JavaScript Master Class for Javascript & UI programmers with Thomas Fuchs (Scriptaculous, Prototype Core) and Amy Hoy (UI Expert) on 9/12 in Washington, DC. Save 10% with code "rubyinside"!
August 21, 2009 at 8:31 pm
I don't understand the Erlang analogy, but there's a similar thing available for Cocoa by way of NuAnywhere: http://programming.nu/nuanywhere
August 22, 2009 at 12:38 am
this is some slick willy!
August 22, 2009 at 1:45 am
Looks cool, but might help if the lib directory was included in the gem .. ; )
August 22, 2009 at 2:09 am
Sorry about that, gem should be fixed now :)
August 22, 2009 at 7:30 am
That would be real cool, will check it out.
can somebody post some tricks which they have tried with it
August 24, 2009 at 9:26 pm
I was trying to hijack our rails process and it got stuck after 'Hijacking...'
Any idea?
OSX 10.5.7
ruby 1.8.7 (2009-06-12 patchlevel 174) [i686-darwin9]
Rails 2.3.2
August 25, 2009 at 3:19 pm
Was the process started with 'script/server'? If so it's a known bug. Use mongrel_rails start or thin start instead.
August 26, 2009 at 3:09 am
Fancy! We got that in perl doing similar things, http://search.cpan.org/~whitepage/Enbugger-2.009/lib/Enbugger.pod
August 27, 2009 at 6:28 pm
I wrote a similar thing for Perl awhile ago (and recently blogged http://use.perl.org/~jjore/journal/39325). The thing I never finished off was dealing with the fact the gdb has attached at an arbitrary instruction and not at a safe time. I spent a short bit of time trying to inform perl that a "signal" had arrived and to wait for the sighandler to run and use that as a break point. That'd get me back to safe signal handling and therefore a perfectly safe time to go launch the debugger.
I'd set the global PL_sig_pending to true, then break on Perl_despatch_signals and try to convince Perl it was ok that there was no actual signal to handle. Didn't quite work.
I suspect you've got the same problem here in Ruby. You should probably "set variable rb_trap_pending = 1" and break on rb_trap_exec or something like that.
August 28, 2009 at 8:55 pm
Thanks for looking.
Yes, it was started with script/server.
Now I can get it hijacked after running as 'mongrel_rails start'
September 3, 2009 at 1:38 pm
Yet another Lisp feature re-implemented in a young programming language.
They grow up so fast! ;)
Really cool stuff though. The next step is to provide a SWANK-like server for running processes. Then you can connect irb to remote processes! Yet another thing Lisp already has.
Great work though. Really pushing the boundaries.