Koz Speaks

Decommissioning This Old Blog

After more than a year with no posts it’s time for me to admit that it’s unlikely I’ll find the time to regularly update a blog. I’ve converted the old posts over to Octopress so that I can avoid the deluge of comment spam and save some CPU cycles. This means I haven’t imported the old comments, there were some great comments but unfortunately there was also a tonne of junk.

My plan is to occasionally post new articles / essays over at Koziarski.com and I’m hoping that a fresh system, without the baggage, will encourage me to expand some of my Twitter rants into something a little more substantial.

The RSS feed here will redirect to the feed for Koziarski.com eventually.

Fun With Threads

During the release of rails 2.2 we made a lot of changes to ensure that we could dispatch requests in parallel by using multiple threads. Some like to describe this as ‘threadsafe’, but as I’ve argued before that’s a little too vague for me.

One of the key lessons we had in the very very early days of rails is that it is impossible to require code when you have multiple threads on the go. It takes a while for people to get their heads around this, typically they ask things like “Why not just put a mutex around require?”. I figured I should write this up for future reference as I haven’t seen it described anywhere else, and people are still learning this the hard way.

This isn’t an issue with autoload. Autoload makes the problem much worse by deferring the require statements to some ‘random’ moment in the future. If you call require from threaded code, you’re going to get bitten by this feature. Let’s start with a simple example:

We’ve all written code like this before, it’s the very basis of how ruby works! Now let’s imagine we want to run this code in multiple threads. Easy right? We’ll require ‘customer’ if it’s not already defined, then do the same thing.

If you run this enough times you’ll get an error like this:

NoMethodError: undefined method `scale!' for #<Customer:0x5f00dc>

WTF is that thing on about? The method is RIGHT THERE! This issue lead some less experienced people to say silly things like “When I used rails in a multi threaded environment methods kept appearing in the wrong thread”. But given how common and underdocumented this issue is, it’s hardly their fault.

The problem comes about because of the way constant definition works in ruby. It isn’t atomic. The second the interpreter has read the “class Customer” line of your file, it has defined the constant Customer, but the constant doesn’t have any methods, or a constructor. It’s like a baby-constant, and if you try to do anything with it, you’ll get all kinds of crazy errors. If you’re playing along at home and want to see this happen, the easiest way is to do this:

Now at first glance this is stupid behaviour, why on earth doesn’t ruby just avoid defining the constant until the very last end statement? Remember back to when you picked up the pick axe and it told you how to define class methods? There are a bunch of different types of syntax available. What about this one?

If Customer wasn’t defined immediately, that syntax couldn’t work! Class methods in ruby aren’t something magical, they’re just methods defined on that particular instance of a Class. Also it’d be impossible to have bi-directional references in your class declarations. ask the delphi guys how much fun that is

So the problem with require and autoload isn’t something about the implementation of how require works, or how autoload works. It’s an inherent limitation of the way ruby works. It’s completely impossible to define constants in one thread, without those constants being accidentally used before they’re ready.

Thankfully we knew about this problem going into the threadsafety project, and the vast majority of the work josh did was to catch all the places where we defined methods and classes, and do that work prior to the dispatcher starting up. This means you pay a penalty at start up, but your application will work correctly irrespective of which constants you reference and when you reference them. We intend to use autoload in non-threaded deployments for 2.3, and to support that we have to preload everything in a similar fashion.

One of the more challenging things with this issue is catching the problem. If all you ever test is a single method, then the first warm-up call will require everything and nothing will break. Hello world is an awful test case here.

So if you’re thinking of trying out jruby and using the nice native threads, be sure to audit every line of code you have for calls to require at runtime, including autoload declarations. If you’re using a framework or library which uses autoload, be sure to work around this problem by requiring everything explicitly ahead of time. If you don’t your code is only ‘thread safe’, and you’re just waiting for trouble.

If you’re a library author and would like a hand figuring out a solution for your case, drop us a line on the rails core list. We’d be happy to help.

Note: I’ve used gist to handle the snippets here, you noscript users will have to trust me :)

Countries and Controversies

The History of Country Select

Before rails 2.0 we received a large number of tickets with modifications to the list of countries in our built in country_select helper. Some of these were people with conflicting preferences, Great Britain vs United Kingdom. Others were questions about whether we should use the english spelling or the native ones, Spain vs Espana.

These patches were a constant distraction and I was concerned about the potential for stepping into controversial issues or legal matters. To my mind there were basically two options: synchronise our list of countries with some neutral source, or remove our list of countries entirely. Given the large number of people who relied on that functionality it seemed simpler at the time to use an ISO standard, and the ISO 3166 Long Names list seemed perfect.

To my mind the ISO list was ‘completely neutral’ and an ‘impartial alternative’, it let Rails have a list that was devoid of my own personal politics. We could avoid any suggestion that we were picking sides in border disputes or questions of recognition and nicely side step the definition of ‘country’ by simply appealing to the ISO.

We received a few patches since we made the switch, and rejected them all by saying “It’s not our place to decide what a country is, please take it up with the ISO”.

Where we find ourselves

However the names of two countries on that list have caused issues for people in recent months. The first was the inclusion of “Palestinian Territories, Occupied”, and the second is the name for Taiwan as “Taiwan, Province of China”. The second issue has recently burst into life again

Given the strength of feelings on the matter we decided to remove the country_select functionality altogether from future versions of rails. Clearly the ISO 3166 list isn’t the ‘completely neutral’ list that I hoped for, and I deeply regret the offense that I’ve caused.

This controversy has been especially frustrating for me because I actually agree with those people who have been upset by this issue. It’s difficult because despite my opinions on the matter, I’ve tried to be as neutral as possible, doing my best to pick the path of least resistance. Unfortunately, it seems that I’ve failed. So here’s my attempt to fix things.

I’m reluctant to make any deviations from the list provided by the ISO organisations as it’ll open the door to several other issues which we’re not qualified to answer. Just a short list of potential complications are:

So we went back to the original decision, and chose the other path. country_select is no longer in rails, and ideally that would be the end of the matter. But to allow users to avoid errors in their applications we added a plugin.

What’s the Way Forward?

As has been pointed out repeatedly, and angrily, this just moves the issue from one git repository to another. Despite the fact that it now warns you when you install it, people will blindly install the plugin, ignore the warning, and piss people off. So I figure there are a few options:

  1. Choose another list of countries provided by some other authority
  2. Remove the plugin and break everyone’s applications come 2.2, unless they want to use the list of alternative plugins which have already sprung up
  3. Remove the taiwan entry from the plugin, so at least the offensive line doesn’t get displayed.
  4. Follow some corporate guidelines such as IBM’s

I’d appreciate any feedback from the Taiwanese rails community about what they think we should do here.