In my previous post I covered troubleshooting unicorn processes. This time I'll share one more technique that can make your devops life easier.
Default unicorn worker process names suck
When you look at server process list using ps auxf
or something similar, unicorn looks like this:
... unicorn master -c /etc/app/config.rb -E production -D
... \_ unicorn worker[0] -c /etc/app/config.rb -E production -D
... \_ unicorn worker[1] -c /etc/app/config.rb -E production -D
... \_ unicorn worker[2] -c /etc/app/config.rb -E production -D
Not very useful, and quite redundant - your workers inherit the argument line from master
process. There's no way to tell what they're doing at given moment.
Overriding unicorn worker process names in Ruby on Rails app
How about something like this?
... unicorn master -c /etc/app/config.rb -E production -D
... \_ unicorn worker[0] 66.249.78.123: last status: 200. Waiting for req.
... \_ unicorn worker[1] 91.9.93.234: GET /items/3134
... \_ unicorn worker[2] 62.227.53.32: POST /auth/login
It shows the IP of your user along with current request method and path. And in case worker is slacking, last user IP and response status. Now, let's make ourselves a piece of Rack Middleware that will do the above.
Create /app/middlewares/set_unicorn_procline.rb
:
class SetUnicornProcline
def initialize(app)
@app = app
end
def call(env)
user_ip = env['HTTP_X_FORWARDED_FOR'] || env['REMOTE_ADDR']
request_info = "#{env['REQUEST_METHOD']} #{env['REQUEST_PATH']}"
worker_line = $0.split(']')[0] + "] #{user_ip}"
set_procline "#{worker_line}: #{request_info}"[0..200]
status, headers, body = @app.call(env)
set_procline "#{worker_line}: last status: #{status}. Waiting for req."
[status, headers, body]
end
def set_procline(value)
$0 = sanitize_utf8(value)
end
def sanitize_utf8(string)
return string.force_encoding('utf-8') if string.valid_encoding?
string.chars.select(&:valid_encoding?).join.force_encoding('utf-8')
end
end
Then enabled it in config/application.rb
:
...
module <YourApp>
class Application < Rails::Application
...
require File.join("#{Rails.root}/app/middlewares/set_unicorn_procline.rb")
config.middleware.use SetUnicornProcline
end
end
It should work with Ruby >= 1.9.3 and Rails >= 3.2.x. The middleware also takes care of broken encoding that would otherwise cause $0.split
to crash on next request after malicious REQUEST_PATH
was provided.
Now run watch 'ps auxf | grep unicorn'
and enjoy the show.