Created
February 22, 2011 23:09
-
-
Save TonyStrauss/839635 to your computer and use it in GitHub Desktop.
Development mode for unicorn (based upon Jonathan Stott's watcher.rb)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# | |
# unicorn_reloader | |
# | |
# spawns a unicorn to serve a rack app in the given directory. Watches | |
# the app files for changes, restarting the unicorn worker when they're | |
# detected. | |
# | |
# Tony Strauss <tony at animoto.com> | |
# Forked in order to: | |
# * Have bring down Unicorn as part of its exit sequence | |
# * Eliminate the need to rely on unicorn's pid file | |
# * Rename (unicorn_reloader) | |
# | |
# This script relies on: | |
# directory_watcher | |
# rev | |
# | |
# This script also echoes the unicorn output to stdout | |
# | |
# This originally was based on Jonathan Stott's watcher.rb (Unicorn Sparkles): | |
# Jonathan D. Stott <[email protected]> | |
# http://namelessjon.posterous.com/magical-reloading-sparkles | |
# | |
# Copyright (c) 2010 Jonathan Stott. | |
# Copyright (c) 2011 Animoto Productions (http://www.animoto.com) | |
# Released under the terms of the MIT License | |
require 'directory_watcher' | |
def usage | |
puts "The unicorn_reloader launches unicorn and monitors source files for" | |
puts "changes. When it detects a change, it restarts the Unicorn workers," | |
puts "reloading the web application. This allows you to" | |
puts "immediately see the results of your changes without any" | |
puts "manual intervention. While doing so, it also tails the specified" | |
puts "log files." | |
puts "" | |
puts "unicorn_reloader unicorn_config_file rackup_file log_file1 log_file2 ..." | |
end | |
if ARGV.empty? | |
usage | |
exit | |
elsif ARGV.length < 2 | |
$stderr.print "Error: invalid arguments!\n\n" | |
usage | |
exit false | |
end | |
log_files = [] | |
unicorn_config_file = ARGV[0] | |
rackup_file = ARGV[1] | |
if ARGV.length > 2 | |
log_files = ARGV[2..ARGV.length] | |
end | |
# The application files that will be watched in order to trigger reloads. | |
GLOB = ['**/*.rb'] # glob of the application's files | |
# remove the old logs | |
log_files.each do |log_file| | |
begin | |
File.delete log_file | |
rescue Errno::ENOENT | |
end | |
end | |
# start unicorn via fork/exec | |
unicorn_pid = Process.fork do | |
Process.exec "unicorn --config-file #{unicorn_config_file} #{rackup_file}" | |
end | |
logs = [] | |
# | |
# Wait for unicorn to start and create any | |
# specified log files. | |
# | |
log_files.each do |log_file| | |
begin | |
logs << File.open(log_file) | |
rescue Errno::ENOENT | |
retry | |
end | |
end | |
# watch our app for changes | |
dw = DirectoryWatcher.new '.', | |
:glob => GLOB, | |
:interval => 2, | |
:scanner => :rev, | |
:pre_load => true | |
# SIGHUP makes unicorn respawn workers | |
dw.add_observer do |*args| | |
puts "Detected source code change. Restarting Unicorn workers!" | |
Process.kill :HUP, unicorn_pid | |
end | |
trap "INT" do |sig| | |
# Kill unicorn, which will trigger the unicorn_relaoder to exit below | |
Process.kill :QUIT, unicorn_pid | |
end | |
dw.start | |
# | |
# Wait for any one of: | |
# * Unicorn to exit (caught by waitpid2) | |
# * unicorn_reloader to be interrupted (resulting in our SIGINT handler being run, which will kill unicorn) | |
# | |
unicorn_exit_status = nil | |
while unicorn_exit_status == nil do | |
logs.each do |log| | |
print log.read | |
end | |
# | |
# The sleep is hacky; this could be improved by using the self-pipe trick | |
# | |
sleep 0.1 | |
# Non-blocking waitpid | |
unused, unicorn_exit_status = Process.waitpid2 unicorn_pid, Process::WNOHANG | |
end | |
dw.stop | |
if not unicorn_exit_status.exited? or not unicorn_exit_status.success? | |
$stderr.puts "\nERROR: Unicorn exited with bad status: #{unicorn_exit_status}" | |
exit false | |
else | |
exit | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment