Search code examples
rubysinatraworker

Will multiple requests accessing the same variable will cause a conflict?


Trying something out I'm not very familiar with:

require 'sinatra'
require 'redis'

$redis = # Connect Redis
$log = []

Thread.new do
  while true do
    $redis.set 'test', $log.pop
  end
end

post '/' do
    $log.push(request.user_agent)
    "ok"
end

Say that I get a couple of thousand hits per second to /. What happens if push and pop are called simultaneously on $log?

Will raising the priority of the worker thread help anything?


Solution

  • You should use use a Queue for this, as it is meant for cross-thread communication. It is thread-safe, and keeps the Thread from busy-waiting as Queue#pop will suspend the thread if there is nothing on the queue instead of looping till the OS takes control away.

    require 'redis'
    require 'sinatra'
    require 'thread'
    
    $redis = # Connect Redis
    $log = Queue.new
    
    Thread.new do
      while entry = $log.pop
        $redis.set 'test', entry
      end
    end
    
    post '/' do
      $log.push(request.user_agent)
      "ok"
    end
    

    However, what you have won’t be an issue (as far as unexpected results go—performance will be a problem) because of MRI’s GIL (other Ruby implementations without a GIL may have issues, though). Also, it would be best to avoid using global variables.