capistrano on_rollback not being called - ruby-on-rails

I'm using capistrano v2 for a Rails 3.2 I have a bundler task in my deploy.rb like so;
# Bundler tasks
namespace :bundler do
desc "Create a symlink"
task :create_symlink, :roles => :app do
shared_dir = File.join(shared_path, 'bundle')
release_dir = File.join(release_path, '.bundle')
run("mkdir -p #{shared_dir} && ln -s #{shared_dir} #{release_dir}")
end
desc "Install required gems"
task :install, :roles => :app do
puts "New Release"
run "cd #{release_path} && #{bundle_path} install"
on_rollback do
if previous_release
puts "Rollback"
run "cd #{previous_release} && #{bundle_path} install"
else
logger.important "no previous release to rollback to, rollback of bundler:install skipped"
end
end
end
desc "Run bundler on new release"
task :bundle_new_release, :roles => :db do
bundler.create_symlink
bundler.install
end
end
after "deploy:update_code", "bundler:bundle_new_release"
after "deploy:rollback:revision", "bundler:install"
When I run cap deploy:rollback it doesn't run the the on_rollback code it tries to run the cd {release_path}.
I got this example from http://kazjote.eu/2010/08/04/bundler-and-capistrano-the-right-way.

Since you didn't give any logs, I can't say for sure if deploy:rollback is deploying the previous version as it should, however you're confusing deploy:rollback (a task), with on_rollback (a hook).
on_rollback would be called only if the task :install failed. However, I also believe you need to define a transaction for the on_rollback hook to actually fire (and possibly have to make the on_rollback definition before your 'run "cd...')
deploy:rollback should run your deploy tasks with the previous successful release.
I found a simpler example here:
http://pedz-bits.blogspot.com/2012/09/capistrano-errors-ensure-and-onrollback.html
namespace :fun do
desc "Sample showing rescue, ensure, and on_rollback inside a transaction"
task :stuff, :roles => :app do
transaction do
on_rollback { logger.debug "my rollback" }
begin
logger.debug "main"
# Either run or run_locally will work the same
# run_locally "false"
run "false"
rescue => e
logger.debug "rescue #{e.class}"
raise e
ensure
logger.debug "ensure"
end
end
end
end
Command output:
cap fun:stuff
* executingD `fun:stuff'
** transaction: start
* main
* executingB "false"
servers: ["condor.austin.ibm.com"]
[condor.austin.ibm.com] executingA command
command finished in 771ms
* rescue Capistrano::CommandError
* ensure
*** [fun:stuff] rolling back
* my rollback
failed: "bash -l -c 'false'" on condor.austin.ibm.com
Notes
on_rollback executes only if the error happens while a transaction is active.
on_rollback must also be defined within the transaction.
raise e to make sure task exits with an error or higher level process will assume it completed successfully.
ensure works as you expect.

Related

No such file or directory during cap deploy:update

I noticed in the output from cap deploy:update, that it is triggering "deploy:assets:precompile" as an after callback for deploy:update_code:
triggering after callbacks for `deploy:update_code'
* 2013-05-15 11:32:16 executing `deploy:assets:precompile'
triggering before callbacks for `deploy:assets:precompile'
* 2013-05-15 11:32:16 executing `deploy:assets:update_asset_mtimes'
* executing "[ -e /home/johnmerlino/public_html/store.johnmerlino.com/shared/assets/manifest* ] && cat /home/johnmerlino/public_html/store.johnmerlino.com/shared/assets/manifest* || echo"
servers: ["xxx.xx.xx.xxx"]
[xxx.xx.xx.xxx] executing command
command finished in 314ms
* executing "cd -- /home/johnmerlino/public_html/store.johnmerlino.com/releases/20130515153214 && bundle exec rake RAILS_ENV=production RAILS_GROUPS=assets assets:precompile"
servers: ["xxx.xx.xx.xxx"]
[xxx.xx.xx.xxx] executing command
** [out :: xxx.xx.xx.xxx] rake aborted!
** [out :: xxx.xx.xx.xxx] No such file or directory - /home/johnmerlino/public_html/store.johnmerlino.com/releases/20130515153214/config/config.yml
** [out :: xxx.xx.xx.xxx
Now the problem there is it says that the latest release doesn't have a "config.yml" file.
Actually in my capistrano script, that file is created after "deploy:update_code":
after "deploy:update_code", "deploy:symlink_shared_configs"
namespace :deploy do
desc "Symlink configuration files"
task :symlink_shared_configs, :roles => [:db,:app] do
run "ln -nfs #{shared_path}/config/database.yml #{release_path}/config/database.yml"
run "ln -nfs #{shared_path}/config/config.yml #{release_path}/config/config.yml"
end
task :start do ; end
task :stop do ; end
task :restart, :roles => :app, :except => { :no_release => true } do
run "#{try_sudo} touch #{File.join(current_path,'tmp','restart.txt')}"
end
end
So shouldn't config.yml be created by this time?
If both are being triggered in the list of callbacks for after deploy:update_code then they're essentially part of the same callback group, but the order in which callbacks in the same group are called depends on the implementation of the callback registration and execution.
If you need them to run in a given order then you can explicitly change when assets:precompile is run by moving it later, or moving the config.yml file earlier in order to guarantee that one comes before the other.
As it stands now, since they both run in the after deploy:update_code the order in which they get executed could be either:
...before...
deploy:update_code
...after... | after group
deploy:symlink_shared_configs | after group
deploy:assets:precompile | after group
...OR...
...before...
deploy:update_code
...after... | after group
deploy:assets:precompile | after group
deploy:symlink_shared_configs | after group
...and based on the fact that you've posted this question, it sounds like the latter instance is happening for you.

rails whenever delete records sql

I tried to a records cleanup after certain period of time (6 month) using gem 'whenever'.
In my whenever scheduler :
every 1.month, at: '1am' do
rake 'lib/tasks/cleanup_user.rake'
end
In the lib/tasks/cleanup_user.rake
#user = User.all.where(:created_at > 'Time.6.month.ago').delete
It seems about right. However, I got error 'uninitialized constant User'. I am relatively new in rails. Please assist me.
EDIT : I changed the game by run clean one line command :
set :output, "log/cron.log"
every 1.minutes, :environment => :development do
command 'User.where("confirmed = 0 AND created_at <= ?", 6.months.ago).delete'
end
I set the specific environment,and run this in command :
whenever --set environment=development --update-crontab userscleaning
Checking at crontab, its there but still not work. Any thought?
Try adding the environment dependency to your task.
task :cleanup_users => :environment do
User.where(:created_at > 'Time.6.month.ago').delete_all
end
If you want the callbacks to trigger, use destroy_all
task :cleanup_users => :environment do
User.where(:created_at > 'Time.6.month.ago').destroy_all
end
Here is a relevant Railscasts.
According to the answers here:
# lib/tasks/delete_old_records.rake
namespace :delete do
desc 'Delete records older than 6 months'
task old_records: :environment do
User.where('created_at > ?', 6.month.ago).destroy_all
end
end
Run with:
RAILS_ENV=production rake delete:old_records
In whenever:
every 1.minutes do
rake "delete:old_records"
end
Or in cron:
0 8 * * * /bin/bash -l -c 'cd /my/project/releases/current && RAILS_ENV=production rake delete:old_records 2>&1'

Need access to current hostname in Capistrano configuration variable for delayed_job named queue

I'm using named queues within delayed_job to keep tasks isolated by server:
subdomain = Socket.gethostname.split('.')[0]
MyModel.delay(:queue => (subdomain + "_queue")).get_some_records
When I start delayed_job on each server, I need to set the --queue flag. One can pass arguments to the delayed_job CL with set :delayed_job_args. AFAIK, Capistrano allows for the use of the $CAPISTRANO:HOST$ in run commands, but this doesn't help me with set.
As a workaround, I have overridden the delayed_jobs task like this:
desc "Start the delayed_job process"
task :start, :roles => lambda { roles } do
run "cd #{current_path};#{rails_env} script/delayed_job start --queue=$CAPISTRANO:HOST$_queue #{args}"
end
Is there any way to do this as intended, using set? I would like to be able to do something like this:
set :delayed_job_args, "--queue=#{ hostname }_queue"
Update
I discovered another kludgy (and not so DRY) way to do this, but still would like to do it with set if possible:
desc "Start the delayed_job process"
task :start, :roles => lambda { roles } do
parallel do |session|
session.when "server.host =~ /server1/", "cd #{current_path};#{rails_env} script/delayed_job start --queue=server1_queue #{args}"
session.when "server.host =~ /server2/", "cd #{current_path};#{rails_env} script/delayed_job start --queue=server2_queue #{args}"
session.else "cd #{current_path};#{rails_env} script/delayed_job restart #{args}"
end
end
Rails 3.2.8, delayed_job 3.0.3, capistrano 2.13.4.
How about … ?
set :delayed_job_args, "--queue=#{ $CAPISTRANO:HOST$ }_queue"
I have not personally tested this in Cap, but it seems logical.

Load ActiveRecord's data to Capistrano's deploy.rb

I'am using Capistrano for deployment and Sidekiq for queues. I need to load user ids to set :sidekiq_queues variable in deploy.rb file to perform sidekiq queues. Now I use following code
set :sidekiq_queues, ::User.all.map {|u| "-q parsing_user_#{u.id}"}.join(" ") + " -q parsing_user_0"
but it throws following error
./config/deploy.rb:29:in `load': uninitialized constant User (NameError)
I tried to require 'rubygems' and 'active_record' into deploy.rb, but it didn't help.
In result I should have
sidekiq_queues == "-q parsing_user_1 -q parsing_user_2 -q parsing_user_3 -q parsing_user_4 -q parsing_user_5 -q parsing_user_0".
Hardcoding queue names isn't a solution.
Capistrano executes deploy.rb locally, and it doesn't load your Rails environment in deploy.rb.
It might be more trouble than it is worth. Especially if you want to execute this on your remote server, you might consider doing a Rake task instead. The => :environment in the rake task ensures that your Rails environment is loaded.
# in deploy.rb
namespace :sidekiq do
desc "Do something with queues"
task :queues, :roles => :web do
run "cd #{current_path} ; RAILS_ENV=#{rails_env} bundle exec rake sidekiq:queues"
end
end
# you'll need to decide when to execute this in your deployment process,
# something like this:
after "deploy:update_code", "sidekiq:queues"
# in lib/tasks/sidekiq.rake
namespace :sidekiq do
desc "Do something with queues"
task :queues => :environment do
queues = (User.scoped.pluck(:id) + [0]).map{|id| "-q parsing_user_#{id}"}.join(" ")
# do what you need to do
end
end

How to just start 1 production Resque worker from Capistrano?

I've got Redis/Resque installed but I'm having a hard time starting/restarting it from Capistrano when I deploy.
My needs are fairly simple: I only have 1 queue, only need 1 worker, and I'm not using monit or god.
Based on this blog post, my deploy.rb has this:
namespace :deploy do
task :start do ; end
task :stop do ; end
task :restart, :roles => :app, :except => { :no_release => true } do
run "#{try_sudo} touch #{File.join(current_path,'tmp','restart.txt')}"
end
task :restart_resque do
pid_file = "#{shared_path}/pids/resque.pid"
run "test -f #{pid_file} && cd #{current_path} && kill -s QUIT `cat #{pid_file}` || rm -f #{pid_file}"
run "cd #{current_path}; RAILS_ENV=production QUEUE='*' VERBOSE=1 nohup rake environment resque:work& > #{shared_path}/log/resque.log && echo $! > #{pid_file}"
end
end
after 'deploy:restart', 'deploy:restart_resque'
My resque.rake file (based on the Railscast) has:
require "resque/tasks"
task "resque:setup" => :environment
When I cap deploy, everything seems to work but there are no workers running when I look at resque-web ...
I suggest you look at this StackOverflow question and this gist for quite a few suggestions.

Resources