duck_punching

Ruby, Rails and tech. No ducks were harmed in the making of this blog.

Passenger (mod_rails) for development. Now with debugger!

Dev mojo

After reading the great posts by Geoffrey “PeepCode” Grosenbach and Manfred Stienstra about using Phusion Passenger for development I had to give it a try. My doctor she’d never heard of mod_rails but gave me antibiotics for it just in case.

After little bit of setup I can say I am much happier with this dev rig than the old ‘script/server’ style. Just open a browser and the app is just waiting to serve you. Nice and agile or something.

Bugger no debugger!

One thing was missing for me though. With no –debugger switch to play with, I needed an alternative. Fortunately the brilliant ruby-debug has the solution with remote debugging. The tricky part was turning remote debugging on or off easily so we didn’t destroy our new dev mojo with onerous meddling in an environment file.

Keepin’ it real (easy)

So your working away and you run into a tough bug in some action or corner of your app. You need to break out the debugger. So the most straight forward way I have found is doing this

rake restart DEBUG=true

But how does it work. Here is a little something I prepared earlier.

In the style of passenger’s restart.txt the restart task also creates debug.txt in the tmp folder if the DEBUG switch is set to true.

Then in development.rb we look for the debug.txt file which triggers ruby-debug to be loaded. We set the ‘wait_for_connection’ option to true which gives us a chance to connect to the remote debugger when the app restarts. Finally start the debugger and clean up the debug.txt file.

From here you refresh the browser and it will it get stuck loading the page. This is because the app is waiting for you to connect to the remote debugger session. In a terminal type

rdebug -c

Once its running you can add and remove debugger statements in the code without needing to restart the debugger or the app. Now you just use the debugger as normal.

If you close the terminal or exit the debug session you can’t reconnect with it. You must do a restart with the DEBUG switch again. Once you cancel the debug session the app won’t drop into the debugger when it hits ‘debugger’ statements any more. So you can continue as normal until you need the debugger again and do a restart.

There you go, thats pretty neat and tidy and agile and whatever.

UPDATE:
I should probably mention that for ease of use and efficiency when using ruby-debug in remote mode you should probably use the ‘set autoeval’ setting. To do that create a file called .rdebugrc in your home directory and put this these lines in for good measure:

set autoeval
set autolist
set autoreload

Follow this link for more info on these settings.

36 comments

36 Comments so far

  1. Geoffrey Grosenbach July 29th, 2008 4:01 am

    Smart! I rarely use the debugger, but it’s nice to know that one can still use it with Passenger.

  2. Mike Vincent August 15th, 2008 7:07 am

    sweet

  3. Yong Bakos August 16th, 2008 6:39 am

    Thanks for sharing this, Adam.

    Have you thought about what else could be done in order to get to irb using this method?

    In the past, when using ruby-debug and mongrel, I’d almost always immediately drop into irb.

    Since this method connects ‘remotely,’ it can’t open an irb session.

    Painful!

  4. Adam August 17th, 2008 1:31 pm

    @Yong: Good point. I had forgotten I use the autoeval setting in ruby-debug which basically eliminates the need to use irb. It evals everything you input in the current scope like using the eval command. Its just as if you were in the irb session.

    If you ever had clash between the rdebug commands and a method or variable name in the current scope, which would happen rarely, you can still use the eval command.

    Just drop ‘set autoeval’ into a .rdebugrc file in your home directory and all ruby-debug sessions will have it turned on by default. I also have ‘set autolist’ and ‘set autoreload’ in there.

  5. Adam (also) August 26th, 2008 11:00 am

    Hi Adam,

    I tried this out but when the debugger connects it never gives me any output. The app is restarting but it still generates the page without pausing. rdebug says it connects though then it just waits.

    I’m using passenger2 on OS X. What’s your setup?

    Thanks,
    Adam. (I’m in Melbourne too :P – too many coincidences)

  6. not adam August 26th, 2008 11:02 am

    might want to change your method of deciding who gets the admin style :P

  7. Adam August 26th, 2008 11:35 am

    Thanks Adam. Will have to fix that. CSS problem on my part I think.

    I am on Ubuntu and passenger 2.0.3. But really the setup shouldn’t matter.

    Just check you are doing it in the right order. So it should be
    1. rake restart DEBUG=true
    2. refresh browser
    3. rdebug -c

    Is that the order you are using?

    When you refresh the browser after the restart but before the connecting to the debugger does the browser hang?

    Lastly if the above is all correct, then you need to check that the debugger statement is definitely being reached in your request.

    Thats all I can think of at the moment.

    Do you go to the Melbourne Ruby/Rails meetups?

  8. Adam (also) August 26th, 2008 12:05 pm

    Yeap thats the order I’m doing things in.

    I’m pretty sure its hitting the debug initialising code in development.rb since it’s letting the debugger connect. If I run `rdebug -c` before the restart it fails to connect which makes sense.

    I just tried setting PassengerMaxInstancesPerApp to 1 to see if it was threading or something but that didn’t help.

    The app is waiting for the debugger to connect, so it doesn’t render until I run `rdebug -c` but as soon as it connects it completes the request.

    rdebug output with me pressing ^C
    $ rdebug -c
    Connected.
    ^C/Library/Ruby/Gems/1.8/gems/ruby-debug-0.10.1/cli/ruby-debug.rb:104:in `gets’: Interrupt
    from /Library/Ruby/Gems/1.8/gems/ruby-debug-0.10.1/cli/ruby-debug.rb:104:in `start_client’
    from /Library/Ruby/Gems/1.8/gems/ruby-debug-0.10.1/cli/ruby-debug.rb:103:in `catch’
    from /Library/Ruby/Gems/1.8/gems/ruby-debug-0.10.1/cli/ruby-debug.rb:103:in `start_client’
    from /Library/Ruby/Gems/1.8/gems/ruby-debug-0.10.1/bin/rdebug:253
    from /usr/bin/rdebug:19:in `load’
    from /usr/bin/rdebug:19

    It looks like it was waiting for input from me, but typing anything to it didn’t do anything.

    I haven’t been to any of the meetups yet, I’m going to try and remember to go this week since the CSS transforms/animations sounds interesting. Might see you there.

  9. Adam August 26th, 2008 12:16 pm

    Does the debugger statement get reached if you use the old style ./script/server –debugger?

  10. Adam (also) August 26th, 2008 1:15 pm

    Seems to behave mostly the same, it hangs until the debugger connects, and deletes the debug.txt file, only difference is it disconnects the debugger client as the request finishes.

    Looks like i’ll have to just uses rdebug script/server when I need to.

    I’m using it on a fairly messy app at the moment. I’ll try it on an edge/2.1 app sometime see if that behaves differently

  11. Adam August 26th, 2008 1:30 pm

    Actually the ‘debug.txt’ shouldn’t come into it if you are using ./script/server –debugger. The extra stuff in development.rb should be ignored and you don’t use ‘rdebug -c’.

    The mongrel process should start and load the local debugger. This means it shouldn’t hang the app on start, only when it reaches a debugger statement.

    It might be that you are on older rails as I can’t remember how older rails handled debugging.

    Good luck.

  12. meekish September 1st, 2008 5:22 am

    Great solution! I decided that loading the whole Rails environment to restart the app was taking too long, so I put this in my ~/.bashrc instead:

    alias resd=’touch tmp/restart.txt; touch tmp/debug.txt’

  13. Gerhard September 4th, 2008 3:00 am

    I have an app frozen to Rails 2.0.2, running under mod_rails 2.0.3. I get the following error:

    stopping only thread note: use sleep to stop forever

    Here is a trace:

    0 /opt/local/lib/ruby/gems/1.8/gems/ruby-debug-0.10.1/cli/ruby-debug.rb 75 in `wait’
    1 /opt/local/lib/ruby/gems/1.8/gems/ruby-debug-0.10.1/cli/ruby-debug.rb 75 in `start_remote’
    2 /opt/local/lib/ruby/gems/1.8/gems/ruby-debug-0.10.1/cli/ruby-debug.rb 74 in `synchronize’
    3 /opt/local/lib/ruby/gems/1.8/gems/ruby-debug-0.10.1/cli/ruby-debug.rb 74 in `start_remote’
    4 /Users/gerhardlazu/code/aspire/config/environments/development.rb 24 in `load_environment’
    5 /Users/gerhardlazu/code/aspire/vendor/rails/railties/lib/initializer.rb 206 in `load_environment’

    It goes all the way down to Passenger. Any ideas on how to get this working with 2.0.2?

    Cheers mate, great write-up!

  14. Adam September 4th, 2008 7:10 am

    I am not sure Gerhard. It should Just Work with Rails 2.x. Can you run ./script/server –debugger with success?

    There is a new version of ruby-debug out 0.10.2 which mentions something about Ruby 1.8.7 compatibility issues. Try updating if you use that Ruby version.

  15. Adam September 4th, 2008 9:18 am

    Actually you might want to hold off on version 0.10.2. I just used it and seems the ‘break’ command is broken of all things. Will post a bug report about it.

  16. Gerhard September 5th, 2008 1:17 am

    Yes, ./script/server –debugger works fine. I’ve started getting the same error under Rails 2.1.0 as well. Any ideas what it might be related to?

    I am running 2 Rails applications under mod_rails, both employing the same ruby-debug approach. When I had a single application, it was working fine. Could my error be related to the 2nd application?

    I’m running ruby 1.8.6 (2008-03-03 patchlevel 114) [i686-darwin9.4.0].

  17. Adam September 5th, 2008 7:12 am

    None at all I’m sorry. Time for experiments. Change one thing and hold all others constant.

    Remove the other app from your passenger setup and try. Then switch. See what happens.

    Other than that playing around I’ve got no idea. You could try upgrading to 0.10.2 just to test if it starts. That version wont be much good for debugging but at least you found something out.

  18. Gerhard September 8th, 2008 8:04 pm

    Ok Adam, I’ll give that a go, I’m back to –debugger for the time being.

    Cheers!

  19. Yong Bakos October 30th, 2008 2:37 am

    Thanks Adam, those config options are a great help.

    Note that you can also set these in environment.rb like so:

    Debugger.settings[:autoeval] = true
    Debugger.settings[:autolist] = true
    Debugger.settings[:autoreload] = true

  20. Yong Bakos October 30th, 2008 2:41 am

    Actually, those should be “= 1″ not “= true” and depending on your version of rdebug the autoreload setting may not be available.

  21. Adam Fortuna November 28th, 2008 3:45 am

    Awesome work. Just what I was looking for.

    Just a note for anyone getting errors though — I had to update my ruby-debug gem to get this working. Before that I was able to start the server, and it would pause at a breakpoint, but when I connected to the server it would show an error (in terminal) and continue. After upgrading the gem it worked like a charm though!

  22. David Dollar December 12th, 2008 6:40 am

    I put together a Rails plugin to make using the ruby debugger under Passenger a lot easier.

    Check it out http://github.com/ddollar/socket-debugger

  23. [...] duck_punching » Passenger (mod_rails) for development. Now with debugger! (tags: ruby rails development programming apache tool passenger debug) [...]

  24. [...] file, the nicest way I’ve found to switch on the debugger comes from the ominously titled duck_punching weblog. It involves adding a rake task to create a debug.txt text file, and adding a snippet of [...]

  25. [...] 2:55 pm on October 19, 2009 Reply Tags: debugging, rails (69), tutorials (5) http://duckpunching.com/passenger-mod_rails-for-development-now-with-debugger – Passenger (mod_rails) for development. Now with debugger! [...]

  26. [...] 下面比较一下二者: 1. 同时对多个本地app进行开发时,passenger比webrick好。因为不需要对于每个app都开一个webrick server,而且对于每个server还需要指定不同的port。 2. 在查看request的信息方面,passenger和webrick差不多。webrick是直接在terminal中显示每个request的信息;而在使用passenger时,则可以通过动态显示development.log的方式进行查看。 3. 在debug方面,webrick会比passenger方便些。在使用webrick时,只需要使用u option来启动server,那么app就会在运行时中断在程序中写有debugger语句的地方。可是,在使用passenger时,debug可能会比较麻烦。目前看到的有两种方式,一种是通过使用remote debug的方式,具体可以参考Passenger (mod_rails) for development. Now with debugger! 。另一种是使用rack-debug,它是一个ruby-debug的interface,其使用方式和webrick没有多大区别,但是唯一一点令我难受的时,对于每个rails app,都需要添加一个middleware来实现rack-debug的功能,但是由于可以通过version control在真正的app里过滤掉这些文件,其实并没有多大影响。 [...]

  27. [...] wait, there is hope: here is a great post on how to debug remotely using ruby-debug. The other option that i tried was using [...]

  28. bobbi March 14th, 2010 12:16 am

    Is the a way to make this work with ruby 1.9 and the ruby-debug19 gem ?

  29. Josh P March 19th, 2010 7:55 am

    Awesome. Thank you.

  30. [...] für Rails-3-EntwicklungWie man den Phusion Passenger für die Entwicklung benutzt wurde schon an einigen Stellen beschrieben. In Verbindung mit Rails 3 gibt es eine kleine Falle. Folgt man diesen [...]

  31. David Esposito September 23rd, 2010 10:31 pm

    A couple of notes:

    I’m not sure when the spawning code was added/changed in Passenger, but the code above will not work with Passenger 2.2.4. Putting the code to launch the debugger in environment.rb (or development.rb) means that it launches within the ApplicationSpawner process and the Rails requests are handled in separate worker processes so your breakpoints will never get hit.

    Section 11.3 of the Passenger guide gives a technique for ensuring that you can hook the spawning of a new request handler. You’ll want to put the code outlined above in the ‘if forked’ block. You will need a little extra code to preserve the state of debug.txt (whether it existed when Apache was tickled) and if your Passenger is configured to allow multiple workers (the default), you’ll have trouble identifying which listener is debugging which process

    http://www.modrails.com/documentation/Users%20guide.html#spawning_methods_explained

    Lastly, you can debug your Rails app from NetBeans by using the ‘ruby-debug-ide’ gem instead of the ‘ruby-debug’ gem.

    Here’s my code in development.rb (it launches the debugger every time without regard to debug.txt)

    if defined?(PhusionPassenger)
    PhusionPassenger.on_event(:starting_worker_process) do |forked|
    if forked
    require ‘ruby-debug-ide’
    Debugger.cli_debug=true
    Debugger.start_server(nil,7000)
    end
    end
    end

  32. Groxx June 1st, 2011 12:36 pm

    Many thanks, David Esposito, that works for me!

    To others out there trying to get it to work: just copy & paste the debugger initialization into David Esposito’s wrapper. `rake restart DEBUG=true` and you’re good to go! The debugger can be connected well in advance of the breakpoints if you have one further into your application.

  33. Dave James Miller March 12th, 2012 2:15 am

    Thanks, even though it’s 3½ years later that’s still very useful! I’ve made it into a Gem to make it even easier to install: https://github.com/davejamesmiller/ruby-debug-passenger

  34. florists in warsaw September 27th, 2012 10:05 am

    I’m curious to find out what blog system you are using? I’m experiencing some small security problems with my
    latest blog and I would like to find something more safeguarded.
    Do you have any suggestions?

  35. unknown May 15th, 2013 2:30 am

    Greetings from California! I’m bored at work so I decided to check out your website on my iphone during lunch break. I really like the info you provide here and can’t wait to
    take a look when I get home. I’m shocked at how quick your blog loaded on my mobile .. I’m not
    even using WIFI, just 3G .. Anyways, fantastic site!

    Feel free to visit my weblog :: unknown

Leave a reply

Mexico