Thor Script for Managing a Unicorn-driven App
Today I deployed a mini sinatra app on one of our test servers to manage some internal QA. I’ve put out quite a few apps backed by Unicorn in QA recently and finally wrote a little script to handle stopping, starting, and reloading of the unicorn processes. Nothing super special here, just thought I’d share a useful script. Drop the following code into your application’s tasks
directory, or place it on the app root and call it Thorfile
.
tasks/unicorn.thor (or Thorfile)
# put me in /path/to/app/tasks/unicorn.thor
require 'thor'
class UnicornRunner < Thor
include Thor::Group
namespace :unicorn
UNICORN_CONFIG = "/path/to/app/config/unicorn.rb"
RACKUP_FILE = "/path/to/app/config.ru"
PID_FILE = "/path/to/app/tmp/application.pid"
desc 'start', 'Start the application'
def start
say 'Starting the application...', :yellow
`bundle exec unicorn -c #{UNICORN_CONFIG} -E production -D #{RACKUP_FILE}`
say 'Done', :green
end
desc 'stop', 'Stop the application'
def stop
say 'Stopping the application...', :yellow
`kill -QUIT $(cat #{PID_FILE})`
say 'Done', :green
end
desc 'reload', 'Reload the application'
def reload
say 'Reloading the application...', :yellow
`kill -USR2 $(cat #{PID_FILE})`
say 'done', :green
end
end
Usage
From your application root directory, run any of the three commands. Keep in mind you’ll need a unicorn config file that actually dictates how Unicorn should behave (like number of workers, where your logs go, etc). You’ll also need a Rackup file ( config.ru
) which tells unicorn how to run your app.
$ thor -T
$ thor unicorn:start Start the application
$ thor unicorn:stop Stop the application
$ thor unicorn:reload Reload the application
$ thor unicorn:start # starts the unicorn master
$ thor unicorn:stop # sends the QUIT signal to master (graceful shutdown)
$ thor unicorn:reload # sends the USR2 signal to master (graceful reload of child workers)
Plop this puppy behind nginx and you’re golden. Thor has a lot more things you could do with this (like overriding which config file to use) by providing method-level options, but this is a great starting point for most people. Leave a comment if you have any improvements or other ways you handle this.