This job shouldn’t be taking this long!
That’s not a great thing to have to say, is it? However, I bet you’ve said it before and may not have immediately know why.
With liberal use of puts and maybe pry, you can figure out what a problem might be next time you run it, but sometimes you need to figure out what that problem is right now.
As it turns out, and I know this is a shocker, Ruby processes are just regular processes. They can be debugged with gdb.
Having recently had the need to find out why a job of mine was running particularly slowly, I found out about this lovely tool the hard way: frantic googling. I found some very useful functions for gdb in a blog post by Rasmus on Ruby callstacks.
define redirect_stdout
call rb_eval_string("$_old_stdout, $stdout = $stdout, File.open('/tmp/ruby-debug.' + Process.pid.to_s, 'a'); $stdout.sync = true")
end
define ruby_eval
call(rb_p(rb_eval_string_protect($arg0,(int*)0)))
end
How to use these:
gdb by running gdb /path/to/ruby PID, where /path/to/ruby is the full path to the actual ruby binary and PID is the process ID of the ruby you want to check out.~/.gdbinit for later).redirect_stdout, which will put all the ruby output into a file called /tmp/ruby-debug.PID where PID in this case if the process id of gdb — not terribly important, but a differentiator in case you do this a lot.ruby_eval('Kernel.caller') and object_id and things like that. You should be able to get local variables from wherever you broke into the program.These ruby_eval commands will output into the tempfile that redirect_stdout created, so you’ll need to tail -f that file in a different console. Now, with that small headache over with, you can see exactly where your program is and if there is a stupid loop where you forgot to check a boundary condition, or what thing you’re doing with a regular expression on where you should have just used String#index.
Written by Jon Yurek.
Imagine you’re working in vim. You come across this code:
gem 'clearance', '1.0.0.rc4'
gem 'neat'
gem 'stripe'
gem 'pg'
gem 'thin'
gem 'rails', '3.2.11'
gem 'bourbon'
gem 'simple_form'
gem 'strong_parameters'
You want to sort the list alphabetically. You select the lines visually:
Shift + V
You invoke the sort function:
:sort
You rejoice:
gem 'bourbon'
gem 'clearance', '1.0.0.rc4'
gem 'neat'
gem 'pg'
gem 'rails', '3.2.11'
gem 'simple_form'
gem 'stripe'
gem 'strong_parameters'
gem 'thin'
You dig deeper:
:help sort
Written by Dan Croak.
Web app development/production parity can be improved by defining process types in a manifest named Procfile such as this one for a Rails app:
web: bundle exec rails server thin -p $PORT -e $RACK_ENV
In production, Heroku’s Cedar stack reads process types from that file.
In development, Foreman manages output streams, responds to crashed processes, and handles user-initiated restarts and shutdowns.
One downside to Foreman is typing http://localhost:3000, http://localhost:3100, etc. into the web browser, incrementing the port number for each app, forgetting which port is which app.
Pow solves this elegantly and is easy to install and maintain.
Pow has a DNS server, capable of port proxying to Rack apps.
Install and run Pow:
curl get.pow.cx | sh
Configure Foreman to always use the same port:
cd /path/to/myapp
echo 'port: 7000" > .foreman
Relate the port to Pow:
echo 7000 > ~/.pow/`basename $PWD`
Use Foreman normally:
foreman start
Reap the benefits of well-named DNS like http://myapp.dev.
It’s possible Pow may see improved, or automatic, Foreman compatibility. Watch this pull request for updates.
Written by Dan Croak.
> How do I learn Ruby on Rails? Vim? Test-Driven Development?
Someone asks us these questions weekly. We think we finally have good answers.
apprentice.io is a program designed around 1-to-1 mentor-to-apprentice relationships with a heavy emphasis on pair programming.
However, each apprentice additionally has extra time each week to study topics of their choice. They set goals with their mentors and are held accountable to reaching them by publicizing the goals in an internal wiki.
Example goals include:
We’ve been calling each apprentice’s wiki page their “trail map”.
To us, the “trail map” metaphor relates to hikers, bikers, and skiiers:
Likewise, apprentices (and anyone learning a topic):

With 12 apprentices in the apprentice.io program, we’ve noticed common patterns in each apprentice’s trail map.
So, we’ve consolidated trails into a default trail map and we’re pleased to now announce its release under a Creative Commons Atribution license.
You’re free to use the trail map however you’d like, even commercial training.
The trails exist as a single git repository on Github named Trail Map:
We hope learners everywhere will fork these trails for their own learning purposes and submit improvements via pull requests.
Each trail has three sections:
This section lists things like books or blog posts to read, screencasts to watch, code to read or write, and koans or tutorials to complete.
In each topic, we aren’t aiming for greatest depth, but rather the most efficient way for the learner to become productive.
For example: we suggest chapters, rather than entire books, to read.
This section lists simple tasks the learner should be able to perform during routine development. We’ve never liked quizzes or certifications, but some hueristic is useful for assessment. We think self-assessment is a simple, fast, and low-stress approach.
For example: we say you know everyday git when you can (among other things), “stage a file, create a commit, and push to a remote branch.”
This section lists things like man pages and API documentation which we’ll always reference regardless of experience. Many things are not worth memorizing.
For example, we suggest that a developer refers to man git-rebase during a
project.
This is a work in progress. We plan to add and edit trails as new resources are released or people tell us better ways they’re learning a topic.
We’d love to get your feedback in the form of Github Issues.
Written by Dan Croak.
Recently, when helping to convert a feature suite to use capybara-webkit, we ran into a problem where, about halfway through, the tests would start erroring out with Errno::EPIPE.
Errno::EPIPE is a “Broken Pipe” error. A pipe in Unix is a way for data to flow from one process to another, and a broken pipe means that one end of the pipe isn’t connected anymore. In this case, the pipe was broken because the webkit-server process that capybara-webkit uses went away. And since well-behaved processes don’t normally go away unless you ask them to, we assumed it was crashing.
With a little of digging, we found the feature that was causing the problem. Annoyingly, the error never popped up when the feature was run alone, meaning it was the interaction of multiple features or steps. After whittling away the options, we found the right situation to force the error: a feature using capybara-webkit followed by one specific scenario in a different feature (which, oddly, didn’t use any Javascript at all). Being able to reliably reproduce the error is a big step towards finding a solution.
Knowing what scenario we were dealing with, we could find the specific step that was the source of the problem. The step makes a call to fork. The way that capybara-webkit closes the browser when the tests are over is by using an at_exit hook, which is called when Ruby is just about to close. Forking a process clones everything about it, including, in the case of Ruby, its at_exit hooks. So, what happened was that the fork executed what it needed to execute and then exited like normal, but it meant that it took the webkit-server process with it because of the at_exit hooks it inherited, leaving no browser to run the javascript-enabled features.
This was good news, though. The webkit-server process wasn’t crashing! It was behaving exactly like it was expected to, but just a little premature. To get around the at_exit hooks, we call exit! in the forked process, which specifically bypasses at_exit hooks. This lets our fork get on with its work, and it keeps the server running for the rest of the test suite to use.
So, if you’re in the position where you have to fork in a cucumber suite and you’re using capybara-webkit, make sure you exit! from the fork, and you’ll save yourself some headaches. If you can help fix this problem for good, pull requests are welcome.