Reputation: 283
I've just seen a unicorn server config like this, in my new project codebase :
worker_processes ENV['UNICORN_WORKERS'].to_i || 2
preload_app true
timeout 30
after_fork do |server, worker|
Thread.new do
begin
RABBIT_CONNECTION = Bunny.new(ENV['AMQP_URL'])
RABBIT_CONNECTION.start
rescue Bunny::TCPConnectionFailed => e
puts "Connection failed"
end
begin
OUTGOING_CHANNEL = RABBIT_CONNECTION.create_channel
rescue Bunny::PreconditionFailed => e
puts "Channel-level exception! Code: #{e.channel_close.reply_code},
message: #{e.channel_close.reply_text}".squish
ensure
RABBIT_CONNECTION.close
end
end
end
From what I know about unicorn is that it is a single-threaded, multi-process web server.
What does this Thread.do
block do? What would happen if all this other code was there without being surrounded in the Thread.do
block?
Upvotes: 0
Views: 480
Reputation: 491
Yes unicorn is a single-threaded, multi-process web server. Here, the Thread.do is being used to asynchronously connect to RabbitMQ using the Bunny client. That is, unicorn doesn't wait for the RabbitMQ connection after creating the process. A thread would wait for the same.
In Unicorn (or MRI ruby for that matter) only one thread can use the CPU at a time. This is accomplished using something called the GIL or the Global Interpreter Lock.
Read this: http://www.jstorimer.com/blogs/workingwithcode/8085491-nobody-understands-the-gil
And this: https://en.wikipedia.org/wiki/Global_interpreter_lock
However, for IO ops like waiting for a connection to the RabbitMQ server, this thread will not use up the CPU cycles and other threads can run on the CPU.
If Thread.do wasn't there, and the RabbitMQ server is unreachable, the process would wait for the server to be available or the connection times out.
Upvotes: 3