Ok boys,

the last two nights I spent on an issue which seems soooooo weird to me, that I have to write about it. I don’t know if it’s because I’m, even after a year of Ruby development, still too much Java-minded and just don’t get the idea of Ruby’s class variables or if they are totally screwed up them self… Anyway, here is my story:

I tried to enhance the StupidBackground plugin a little. It should be possible to assign workers to a certain “runner”, so that it would be easy to have more than one background runner. Maybe one for your quick running tasks and one for the ones that take eons to finish.

Until tonight we stored the list of tasks a runner should run in a class variable of that runner. That worked out fairly good until I made the changes described above. After these changes the code runs somehow like this:

  • Run “main runner”
  • Check all Worker classes
  • If a worker uses a different worker than the default one, start another worker and fork it away (via Daemonized)
    • This forked away runner checks all workers again for the ones, using it
    • After the fork the “main runner” continues with the worker checking and maybe forks away more runners, when needed.

That means there is a process which forks away more and more processes and there are class variables. To make a long story short: An awful idea! All the processes shared the class variables! Which led to a state where every runner ran every task. As I said before, it took me quite a while to debug this, but finally the guys from #ruby-de on irc.freenode.org bailed me out.

So if class variables are the problem, was is the solution? Instance variables! Pretty good idea, but what to do in a class context like:

1
2
3
4
5
  class Blah
    def self.foo
      #what to do here?
    end
  end

As I said before my mind is still polluted with Java so I forgot about an important fact at this point: Class is a full-fledged object. So there would be no problem with using instance variables in this context. Ok, you have to understand that those instance variables are not accessible as an instance variable in the instance context of this class but I think this is comprehensible.

But I’m still astonished that the following is possible:

1
2
3
4
5
6
7
8
9
10
  class Blah
    def self.foo
      @test_var ||= Array.new
      @test_var << @test_var.size
    end
  end
 
  p Blah.foo # [0]
  p Blah.foo # [0,1]
  p Blah.foo # [0,1,2]

This might be not new to you if you really know Ruby, but if you’re just slowly getting to it from some other language such concepts might be hard to remember when you need them. But I hope with this post I can jog your memory :) .

Kudos to the guys at #ruby-de for the nice and quick help!

Yours,

Thorben
FEtMab-Team

Related posts