Archive for the 'programming' Category

Introduction to Heroku H12 timeouts

Tuesday, November 15th, 2011

At Exvo we were experiencing problems while trying to send an email to all of our 150K+ users. This lead to a careful investigation of what is exactly happening during this process. So we setup our loggers (heroku logs -t | tee output.log), run heroku consoles, increased to 20 dynos and 10 workers and begun the sending process.

It all started with a POST request to send those emails:

app[web.10]: Started POST ...

Which timed out and there was no:

app[web.10]: Completed 200 OK ...

or similar log entry later on, just silence.

This is Heroku’s killing machine in action. It silently kills every process, which runs for longer than 30 seconds (we’re using the Bamboo stack). This is more or less how Heroku deals with long running requests. I don’t blame them for this behavior, even though I very much dislike it. But I digress.

When Heroku kills such process it does so in a very nice way, i.e. it lets it finish its business first. In other words the process will continue in the background and after finishing it will just die/stop/restart. Our email collecting job (selecting 150K users from the database…) run uninterrupted for over 40 minutes. So this is the good part.

The bad part is that when this killed process is still running in the background the dyno which it was connected to will stop serving new requests until this process finally dies, but Heroku will keep sending new requests to it! This is observed by the infamous H12 timeouts:

heroku[router]: Error H12 (Request timeout) -> GET auth.exvo.com/users/sign_in dyno=web.10 queue= wait= service=30000ms status=503 bytes=0

Also notice the 503 error code (Unavailable), which is returned by the Heroku router.

So this is really bad as all sorts of different/random web requests will just keep failing without you knowing what’s going on.

So while I greatly appreciate that Heroku lets such processes still run in the background, I really don’t like that it still keeps sending traffic their way.

PS: Yes, sending emails should be done as a background action by the Heroku workers. I know. But it’s not. Yet.

In Ruby ‘?’ binds stronger than ‘or’

Thursday, October 13th, 2011

Found it the hard way.

Improper/misleading:

true or true ? "yes" : "no"
=> true

the above is basically the same as this:

true or (true ? "yes" : "no")
=> true

The proper way:

true || true ? "yes" : "no"
=> "yes"

Tell bundler to install gems globally when using capistrano

Saturday, October 8th, 2011

Seems like it’s not so straightforward. Here’s the excerpt from my config/deploy.rb:

require "bundler/capistrano"
set :bundle_dir,     ""         # install into "system" gems
set :bundle_flags,   "--quiet"  # no verbose output
set :bundle_without, []         # bundle all gems (even dev & test)

Maybe someone finds it helpful.

Painful ruby 1.9.2-p180 to 1.9.2-p290 upgrade

Saturday, October 8th, 2011

I did the recommended upgrade of my current p180 to the new p290 using rvm:

$ rvm upgrade ruby-1.9.2-p180 ruby-1.9.2-p290

First annoyance – moving gems from one gemset to the new one took over 40 minutes. Have really no idea why.

But after it was done, whenever I tried to run ‘gem’ or ‘rake’ or ‘bundle’ I got:

Invalid gemspec in [/home/jkl/.rvm/gems/ruby-1.9.2-p290/specifications/guard-0.8.1.gemspec]: invalid date format in specification: "2011-09-29
00:00:00.000000000Z"
Invalid gemspec in [/home/jkl/.rvm/gems/ruby-1.9.2-p290/specifications/json-1.6.1.gemspec]: invalid date format in specification: "2011-09-18 0
0:00:00.000000000Z"
Invalid gemspec in [/home/jkl/.rvm/gems/ruby-1.9.2-p290/specifications/heroku-2.8.4.gemspec]: invalid date format in specification: "2011-09-23
 00:00:00.000000000Z"
Invalid gemspec in [/home/jkl/.rvm/gems/ruby-1.9.2-p290/specifications/guard-0.8.4.gemspec]: invalid date format in specification: "2011-10-03
00:00:00.000000000Z"
Invalid gemspec in [/home/jkl/.rvm/gems/ruby-1.9.2-p290/specifications/multi_xml-0.4.0.gemspec]: invalid date format in specification: "2011-09
-06 00:00:00.000000000Z"
Invalid gemspec in [/home/jkl/.rvm/gems/ruby-1.9.2-p290/specifications/heroku-2.8.1.gemspec]: invalid date format in specification: "2011-09-21
 00:00:00.000000000Z"
Invalid gemspec in [/home/jkl/.rvm/gems/ruby-1.9.2-p290/specifications/metrical-0.0.7.gemspec]: invalid date format in specification: "2011-09-
11 00:00:00.000000000Z"
...
and so on...

The above is another manifestation of the YAML engine switch from Syck to Psych and all of the incompatibilities it has brought. The problem is that now you have to reinstall all of your gems, because all installed gems have wrong gemspec specification. D’oh.

I fixed it by running:

$ rvm gemset empty

And then bundling in each project…

$ bundle

Some more reading material.

Bug of the day

Wednesday, September 28th, 2011

Completely bad code follows, beware.

Silent error in Ruby 1.8.7:

x = [:a, :b]
=> [:a, :b]

x.slice!(:a)
=> nil

x
=> [:a, :b]

Explicit error (resulting in a failing test) in Ruby 1.9.2:

x = [:a, :b]
=> [:a, :b]

x.slice!(:a)
TypeError: can't convert Symbol into Integer

Just yet another incompatibility, but for the better!

Run guard-jasmine-headless-webkit without X server

Friday, September 9th, 2011

You write specs for your javascript, right? If not, you really should.

jasmine-headless-webkit really helps with that. guard-jasmine-headless-webkit makes it all even more enjoyable, although there’s one caveat – it’s not so easy to set it all up.

There is a great guide for that, but it lacks some important details on running guard-jasmine-headless-webkit without graphical interface (X server).

Assuming you already have Xvfb installed, execute this command to run Xvfb in the background:

Xvfb :0 -screen 0 1024x768x24 > /dev/null 2>&1 &

And then you need to setup the DISPLAY shell variable in order for guard-jasmine-headless-webkit to automatically connect to our virtual frame buffer. Here’s the excerpt from my .bash_profile (it first checks if there is Xvfb running on display :0 and only then sets the DISPLAY variable):

xdpyinfo -display :0 &>/dev/null && export DISPLAY=:0

Hash to HTML (hash2html) in Ruby

Monday, September 5th, 2011

I needed to output a Hash as a nested HTML structure. Googling didn’t find any satisfactory results, so I decided to roll my own. UL/LI tags seemed like the best choice. It was a nice exercise in recursion.

The result is a function, which outputs a nicely indented HTML. Note, however, that it’s a very basic solution. It doesn’t cope well with anything other than Strings and Numbers (unless your objects support a nice to_s method).

# Prints nested Hash as a nested <ul> and <li> tags
# - keys are wrapped in <strong> tags
# - values are wrapped in <span> tags
def HashToHTML(hash, opts = {})
  return if !hash.is_a?(Hash)

  indent_level = opts.fetch(:indent_level) { 0 }

  out = " " * indent_level + "<ul>\n"

  hash.each do |key, value|
    out += " " * (indent_level + 2) + "<li><strong>#{key}:</strong>"

    if value.is_a?(Hash)
      out += "\n" + HashToHTML(value, :indent_level => indent_level + 2) + " " * (indent_level + 2) + "</li>\n"
    else
      out += " <span>#{value}</span></li>\n"
    end
  end

  out += " " * indent_level + "</ul>\n"
end

Who knows, maybe someone somewhere finds it useful.

Update: much more concise solution by Piotr Szotkowski.

My first pull request to a public project has been accepted

Wednesday, August 31st, 2011

It was a small but important patch to the i18n gem‘s pluralization rules for the Polish language.

Really made my day. Thanks Krzysztof!

Hash#fetch

Tuesday, August 30th, 2011
{}.fetch(:a) { 0 }
=> 0

I think it’s really beautiful. Oh, and it’s Ruby, btw.

Update: this is even better:

{}.fetch(:a) { {} }
=> {}

hookup is the shit!

Monday, June 6th, 2011

This is simply amazing:

$ g pull
Already up-to-date.

$ g co edge
Switched to branch 'edge'
==  AddFileTypeToSong: migrating ==============================================
-- add_column(:songs, :file_type, :string)
   -> 0.0048s
==  AddFileTypeToSong: migrated (0.1380s) =====================================

$ g rebase master
Current branch edge is up to date.

$ g co master
Switched to branch 'master'
==  AddFileTypeToSong: reverting ==============================================
-- remove_column(:songs, :file_type)
   -> 0.1674s
==  AddFileTypeToSong: reverted (0.1679s) =========================

Oh, and it will bundle automatically for you as well, so don’t hesitate and hookup your Rails project!