I don't have time to read and I want to jump immediately to the solution.
Like the 90% of Rails developers, I use Capistrano to manage the deployment of my Rails applications. I also use God to monitor several application processes, such as DelayedJob workers.
The problem
Each time I execute a deployment, I need the restart all the Rails instances, including rake tasks and workers, otherwise they will continue to run with the previous (old) application version.
I cannot simply send a command to God via Capistrano because God is omnipotent and runs with root
privileges, while Capistrano doesn't (for security reasons I don't deploy with a sudoer user).
Here comes the problem. How to restart God when you deploy a new release? I already discussed this problem in the past and the solution I adopted since today was to execute a command as root without using sudo. The problem with this solution, is that it requires you to type the root password each time you execute a new deploy. And this is extremely awkward.
Last week I was configuring a new Ruby on Rails application and I decided to investigate a new solution. I really like the way how Phusion Passenger works: whenever you touch the /tmp/restart.txt
file, Passenger restarts all the Rails processes.
Why not implementing the same behavior in God? Luckily, someone else already had the same idea before.
The solution
I found the following recipe on Gist.
module God
module Conditions
class RestartFileTouched < PollCondition
attr_accessor :restart_file
def initialize
super
end
def process_start_time
Time.parse(`ps -o lstart -p #{self.watch.pid} --no-heading`)
end
def restart_file_modification_time
File.mtime(self.restart_file)
end
def valid?
valid = true
valid &= complain("Attribute 'restart_file' must be specified", self) if self.restart_file.nil?
valid
end
def test
process_start_time < restart_file_modification_time
end
end
end
end
Save the code in your God application or on the server and make sure God loads it. My suggestion is to add the following line in the God configuration script (e.g. /etc/god/config
)
# Load in all God shared configs.
# Share configs apply to all instances.
God.load "/etc/god/conf.d/*.god"
and save the file in the /etc/god/conf.d
folder. In this way, when you'll start God with
$ god -c /etc/god/config
all the shared recipes will be loaded.
Then, configure the monitored process to watch the restart file. The configuration is available as a state transition condition.
rails_root = "/path/to/rails"
restart.condition(:restart_file_touched) do |c|
c.interval = 5.seconds
c.restart_file = File.join(rails_root, 'tmp', 'restart.txt')
end
Taking the GitHub DelayedJob recipe as example, you should change
# restart if memory gets too high
w.transition(:up, :restart) do |on|
on.condition(:memory_usage) do |c|
c.above = 300.megabytes
c.times = 2
end
end
to
# restart if memory gets too high
w.transition(:up, :restart) do |on|
on.condition(:memory_usage) do |c|
c.above = 300.megabytes
c.times = 2
end
on.condition(:restart_file_touched) do |c|
c.interval = 5.seconds
c.restart_file = File.join(rails_root, 'tmp', 'restart.txt')
end
end
The restart_file
can be whichever file you want. I strongly encourage to use the same /tmp/restart.txt
Passenger file, in this way your processes will restart each time you restart the application.
Thanks to Nathan Humbert for creating the original God configuration.