5

I have created a feature that publish a news with the language of the page's creator.

Here is the code that create the news :

def add_news
  locale = creator.language.blank? ? I18n.locale : creator.language
  I18n.with_locale(locale) do
    title = I18n.t('news.subject')
  end
  create_news({title: title})
end

It works good, the news is created with the good language. But sometimes, a wrong language is used. I have read the sourcecode of i18n (https://github.com/svenfuchs/i18n/blob/master/lib/i18n.rb), and for me the with_local function is not threadsafe. I was very surprised beacause I have read no post on that problem.

So, waht do you think about that ? Threadsafe or not ? Do you know a other solution if so ?

Thanks and br,

Eric

elhostis
  • 1,067
  • 14
  • 32

2 Answers2

3

Looks like it is from the Ruby on Rails guides as it is using Thread.current.

Also ran a small (conclusive) experiment:

n = I18n.available_locales.length
10.times do |i|
  loc = I18n.available_locales[i % n]
  Thread.new do
    I18n.with_locale(loc) do
      puts "#{loc} #{I18n.t 'one.of.your.keys'}"
    end
  end
end
  • It's worth noting that this is a simulation of an unrepresentative scenario. The reason thread safety issues arise with Rails's I18n module is because it allows leaking state between requests when using multi-threaded web servers like Puma or Thin. The response by @stevepentler below is clarifying. – jmromer Aug 14 '21 at 22:11
1

Thread.current is not thread safe for threaded web servers like Puma or Thin. See github.com/steveklabnik/request_store for a more detailed explanation:

The problem

Everyone's worrying about concurrency these days. So people are using those fancy threaded web servers, like Thin or Puma. But if you use Thread.current, and you use one of those servers, watch out! Values can stick around longer than you'd expect, and this can cause bugs. For example, if we had this in our controller:

  def index   
    Thread.current[:counter] ||= 0   
    Thread.current[:counter] += 1
    render :text => Thread.current[:counter]
  end

If we ran this on MRI with Webrick, you'd get 1 as output, every time. But if you run it with Thin, you get 1, then 2, then 3...

jmromer
  • 2,212
  • 1
  • 12
  • 24
stevepentler
  • 261
  • 2
  • 4
  • This doesn't mean that Thread.current is not thread safe. It is thread safe, in that every thread has its own hash and t threads will not see or write to each other's data. It is not PER REQUEST which is presumably what you're striving for. So Puma and Thin's behaviour is totally expected. That said I have no idea why Webrick would be clearing Thread.current out each request. – Jack Casey Oct 12 '20 at 06:42