Wednesday, May 6

A better progress meter for your (Rails) scripts

As a follow-up to my post a couple weeks back on putting a progress meter in your long-running migrations, I've whipped up a more helpful and re-usable tool.

I've called it simply "Progress" and here it is in its entirety:

class Progress
require 'action_view/helpers/date_helper'
include ActionView::Helpers::DateHelper

def initialize(total, interval = 10)
@total = total
@interval = interval
@count = 0
@start =

def tick
@count += 1
if 0 == @count % @interval
sofar =
elapsed = sofar - @start
puts "been running for #{distance_of_time_in_words(@start, sofar)}"
rate = elapsed / @count
puts "at a rate of #{distance_of_time_in_words(sofar, (sofar - rate), true)} per item"
finish = sofar + ((@total * rate) - elapsed)
puts "should finish around #{distance_of_time_in_words(sofar, finish)}"

Usage is pretty simple. Here's an (slightly-abridged) example from a Rake task I wrote to clean out bad references to removed YouTube videos:

namespace :videos do
desc "Remove videos from SpumCo if YouTube also removed them"
task :purge => :environment do
videos = Video.find(:all, :order => 'created_at asc')
progress =
videos.each do |video|
video.destroy unless video.still_on_youtube?

And what you see in the console as the script runs is periodic updates like so:

been running for less than a minute
at a rate of less than 5 seconds per item
should finish around 14 minutes

No comments: