I want to store and update an Enum in an thread-safe way in my sinatra app. I use unicorn. I tried the following:
#!/usr/bin/ruby
require 'sinatra'
$locked = false
$num = 0
class App < Sinatra::Base
before do
while $locked do end
$locked = true
end
after do
$locked = false
end
get "/wait" do
sleep 10
$num += 1
erb :display
end
get "/winner" do
$num += 1
erb :display
end
end
The view just shows $num ;)
I started the app with unicorn (4 workers) and visited http://localhost:8080/winner
with my browser.
I clicked on refresh several times, but the app didn't show the expected behaviour (1,2,3,4,5,...) it instead showed random numbers (1,1,2,1,2,3,2,3,2,3,4,...)
so how do I get this thread-safe? :D (sorry for my bad english)
Your issue isn't so much thread safety (although there is a slight race condition here - use a mutex rather than your $locked variable) as the fact that each unicorn worker is a separate process.
Each of these processes has a separate set of global variables, so the code you've written fundamentally can't work, no matter how much synchronisation you add to each process.
The ususal way to approach this would be to store the number in some shared datastore, for example a database like mysql, mongo, redis or even memcached. The last 3 of those have a specific atomic create or increment operation, but you can do this in a relational database too.