Counting open files by process

A site I host is offline, throwing the error “Too many open files.” The obvious solution would be to bounce the webserver to release all the file handles, but I wanted to figure out what was using all of them and see if I could figure out why they were leaking in the first place.

I had a few hunches, so I ran lsof -p PID on a few of them. But none of them had excessive files open. After a couple of minutes of guessing, I realized this was stupid, and set out to script things.

I hacked this quick-and-dirty script together:


pids = Dir.entries('/proc/').select{|p| p.match(/\d+/)}
puts "Found #{pids.size} processes..."
pfsmap = {}
pids.each do |pid|
files = Dir.entries("/proc/#{pid}/fd").size
cmdline = File.read("/proc/#{pid}/cmdline").strip
pfsmap[pid] = {
:files => files,
:name => cmdline
}
end

puts pfsmap.sort{|a,b| a[files] <-> b[files]}

There’s got to be a better way to get a process list from procfs than regexp matching directories in /proc that are only numeric. But I do that, and, for each process, count how many entires are in /proc/PID/fd and sort by that. So that the output isn’t just a giant mess of numbers, I also read the /proc/PID/cmdline.

This is hardly a polished script, but it did the job — it identified a script that was hitting the default 1024 FD limit. I was then able to lsof that and find… that they’re all UNIX sockets, so it’s anyone’s guess what they go to. So I just rolled Apache like a chump. Oh well. Maybe it’ll help someone else—or maybe someone knows of a less-ugly way to do some of this?

Software Circuit Breakers in Ruby

I found an interesting article in this week’s Ruby Weekly newsletter—a post from Martin Fowler about the circuit breaker concept in Ruby.

The idea is pretty simple, but pretty slick: wrap calls to external services that can fail in a ‘circuit breaker’, which will detect when the call is failing (or acting particularly slow) and short-circuit calls. In the simplest case, this can help avoid slow-downs when a non-critical remote service fails. For example, if you normally made an inline call to send a welcome email to new signups, you might fall back to just enqueuing the task if the mailserver call slows down—or perhaps just take them to a webpage with the same content.

In the best case, this can prevent cascading failures. Webpages make a blocking call to an external service, which goes down, thus filling up the queue of available application servers, thus leading to a service outage.

Cool Link Roundup

A bunch o’ interesting links I’ve happened across recently:

Presence in Rails

One thing that might not be immediately obvious is that an empty string in a conditional in Ruby will return true. See for yourself:

irb(main):006:0> puts "Whoa" if ""
(irb):6: warning: string literal in condition
Whoa

The same holds true for other empty things — say, arrays:

irb(main):008:0> puts "See?" if []
See?
=> nil

Pure Ruby will let you call .empty? (on some methods — it’s not standard on Object though!), but code like this is silly and it’s easy to forget:

irb(main):003:0> puts "We have some meaningful value" if str and !str.empty?
=> nil

But Rails makes this easy for us. Rails extends Object to add a present? method. present? is literally defined as !blank?, which is almost always what I actually want to check for: it’s not nil, or “blank”, like a string that’s just whitespace, or empty constructs like [] or {}:

irb(main):009:0> nil.blank?
=> true
irb(main):010:0> [].present?
=> false
irb(main):011:0> "     ".present?
=> false
irb(main):012:0> 0.present?
=> true

Hardly an earth-shattering development, but it’s a handy tool that seems underused.