This is a mobile version, full one is here.

Yegor Bugayenko
26 June 2019

SyncEm: Thread-Safe Decorators in Ruby

I wrote some time ago about thread-safety in OOP and how it can be achieved with decorators. It was also said that it’s very important to make sure objects are thread-safe (in Ruby and in Java), especially in web apps, which are multi-threaded (well, in most cases anyway). Well, here is SyncEm, a primitive Ruby gem which makes the above possible with a single decorator.

Look at this simple Ruby web app, which increments the internal counter on every web click:

require 'sinatra'
class Front < Sinatra::Base
  configure do
    set(:visits, Visits.new)
  end
  before '/*' do
    settings.visits.increment
  end
  get '/' do
    "Your visit is no.#{settings.visits.total}"
  end
end
Front.run!

In order to count visits it uses class Visits, which may be defined this way (it keeps the counter in a file):

class Visits
  def increment
    idx = IO.read('idx.txt').to_i + 1
    IO.write('idx.txt', idx.to_s)
    idx.to_s
  end
  def total
    IO.read('idx.txt').to_i
  end
end

It is not thread-safe. Try to run this app and you will see that, if you make many concurrent HTTP requests to the front page, the counter will not always return consecutive numbers.

To make it thread-safe you can use SyncEm, a small Ruby gem, which I created just a few months ago. Here is how:

require 'syncem'
class Front < Sinatra::Base
  configure do
    set(:visits, SyncEm.new(Visits.new))
  end
  # Same as above
end

Here we just decorate the object with a thread-safe decorator, which intercepts all calls to all methods of an object and make them all synchronized with a single encapsulated semaphore:

SyncEm.new(Visits.new)

This mechanism will only work in Ruby or similar interpreted languages. I would not be able to do the same in Java or C++. But in Ruby, Python, PHP, JavaScript and many others, similar decorators may be very useful.

I’m using it in this web app, for example.