The problem
We have Sidekiq installed on the production server, and we use Monit to monitor its processes. The problem is that when we deploy with Capistrano, Capistrano stops the existing process and starts a new one at the end of the deploy. Meanwhile Monit, notices that the Sidekiq process has stopped, and restarts it. After the deployment, there are two Sidekiq processes running, instead of one.
The Monit recipe looks like this:
check process <%%= fetch(:sidekiq_service_name) %>
with pidfile <%%= fetch(:sidekiq_pid) %>
if does not exist then alert
start program = "/bin/bash -c '<%%= fetch(:sidekiq_comand) %> -d -i 0 -P <%%= fetch(:sidekiq_pid) %> -e production -C <%%= fetch(:sidekiq_config) %> -L <%%= fetch(:sidekiq_log) %>'" with timeout 30 seconds
stop program = "/bin/bash kill -s TERM `cat <%%= fetch(:sidekiq_pid) %>`" with timeout 30 seconds
if totalmem is greater than 500 MB for 2 cycles then alert
group sidekiq
The solution
The solution is to tell Monit to unmonitor the Sidekiq before deploy and monitor it again when the deployment is complete. The hooks that perform that below are taken from the capistrano-sidekiq gem, so feel free to use that gem if easier. Otherwise, read on.
Let's write the Capistrano tasks that will unmonitor/monitor Sidekiq on a recipe accessible by production stage, e.g. config/deploy/production.rb
file.
namespace :sidekiq do
namespace :monit do
desc "Monitor sidekiq"
task :monitor do
on roles(:app) do
execute "sudo /usr/bin/monit monitor #{fetch(:sidekiq_service_name)}"
end
end
desc "Unmonitor sidekiq"
task :unmonitor do
on roles(:app) do
execute "sudo /usr/bin/monit unmonitor #{fetch(:sidekiq_service_name)}"
end
end
end
end
And then we'll tell Capistrano to run them before and after deployment:
namespace :deploy do
after 'deploy:check', 'sidekiq:monit:unmonitor'
after 'deploy:publishing', 'sidekiq:monit:monitor'
end
When we deploy again, all should work OK, and we'll have only one Sidekiq process running.