I have and rails application and a rake task which I'm going to execute by cron around once in an hour. But the thing is that the task uses rails environment and some classes of my rails application. If I run it as ruby script, I'll have to include all the dependencies it uses and I think it's not possible to do it correctly and in a simple way. So I'll have to run it as a rake task because it'll preserve all the dependencies, right? Then how can I run a rake task from cron?
Note that I prefer not to use any third-party solution when there's no necessity, in this case I don't want to use the gem whenever or the like.
You can add to your crontab something like
0 * * * * /bin/bash -l -c 'cd /path/to/your/project && bundle exec rake foo:bar >> log/cron.log 2>&1'
This will run foo:bar task every hour and write stdout and stderr to log/cron.log.
Please notice bundle exec before rake command.
Using bundler ensure you that task will fetch correct environment.
To specify RAILS_ENV you can do
... && RAILS_ENV=production bundle exec rake foo:bar
Use whenever to simplify your life https://github.com/javan/whenever ;)
Here's an example of a rake task:
task :foo => :environment do
puts "Running rake task in environment: #{Rails.env}"
# can access Models here or whatever
end
Note that the => :environment part is optional, but it what makes your Rails environment to the task block.
You can put rake run_my_task in your cron job.
You may need to use something like cd /home/$USER/my_rails app && rake run_my_task to ensure that the cron runs the task from the Rails root directory.
Related
Suppose I have a model method
def self.do_something
How do I run this method after deploy in capistrano? I've tried runner, I've tried making a rake task, nothing works. Can someone provide an exemplar?
Thanks,
kevin
You have to load the rails environment before calling your rake task in your deploy file, Capistrano doesn't do it.
run "cd #{current_path} ; RAILS_ENV=#{rails_env} bundle exec rake my:task"
I've written a rake task for my Rails application and I'd need to run this tasks regularly with using CRON.
If I have a URL that I need to ping with CRON, I do it like this:
0 */6 * * * curl https://www.website.com/something
But how to "ping" a rake task?
The application is located in /home/deployer/apps/myapp-production/current and is running on DigitalOceal (Ubuntu server - nginx).
Thanks.
EDIT: This is my command:
0 */6 * * * cd /home/deployer/apps/myapp-production/current && RAILS_ENV=production bundle exec rake db:backup
But the output is:
/bin/sh: 1: bundle: not found
When I run just rake db:backup on my laptop (locally), everything works just well.
Do I have incorrect the path in the CRON task?
EDIT2: When I run the command cd /home/deployer/apps/myapp-production/current && RAILS_ENV=production bundle exec rake db:backup manually from the command line, everything is working, but not from the CRON.
Use whenever gem. It provides nice DSL like:
every :day, :at => '12:20am', :roles => [:app] do
rake "app_server:task"
end
Running Rake tasks can be awkward.
The commands tend to be really long.
For example...
$ bundle exec rake some_project:clear_expired_sessions
Also, I may not always remember the exact name of some task I only use occasionally.
So I have to discover task's name first like this and then copy and paste it into the command line...
$ bundle exec rake -T some_project
I'm using Zsh on OS X with oh-my-zsh and the Rake plugin.
It provides tab-completion of Rake tasks, but you still have to type "bund exec rake" the completions are really slow to load -- several seconds on my machine.
Is there a more efficient way?
You can always add an alias to your .bashrc or your .bash_profile to avoid bundle exec rake in the future.
alias rake='bundle exec rake'
Of course now bundle exec is implicated whenever you run rake, its up to you to decide if you want that.
or for project specific (lets say your project is rails_blog)
alias rkblog=railsblogtasks()
function railsblogtasks(){
cd /path/to/blog/;
bundle exec rake -T;
end
alias rkblogrun=runblogtask()
function runblogtask(){
cd /path/to/blog/;
bundle exec rake $1;
end
Now $ rkblog will show all your rails_blog tasks and $ rkblogrun <task> will run any task in your rails_blog project. This can of course be refactored and abstracted, but there is a general idea.
One quick simplication:
task :example_alias => :environment do
Rake::Task[some_project:clear_expired_sessions].invoke
end
Then you can simply do
$ rake example_alias
I've ruby on rails application running in production, this apps have STOCK model and it should be updated every 1 minute.
For updating this model i create simple rake task db:populate:stocks, when it contain only two operation :
truncate the STOCK model
fill STOCK model with latest data fetch from webservice
this rake task should be execute every 1 minute, for this purpose i use whenever gem. Here my schedule.rb :
env :PATH, ENV['PATH']
set :job_template, nil
set :output, {:standard => '/home/admin/shared/log/cron.log', :error => '/home/admin/shared/log/cron-error.log'}
job_type :rake, "cd :path && rake :task RAILS_ENV=:environment --trace :output"
every 1.minute do
rake "db:populate:stocks"
end
In production i'm using rvm running ruby 1.9.2-p180, rails 3.1.0 and capistrano, here my capistrano task for update cron tab :
after "deploy:update_code" do
run "cd #{release_path} && whenever --clear-crontab RAILS_ENV=production"
run "cd #{release_path} && whenever --update-crontab RAILS_ENV=production"
end
And my schedule.rb create cron task like :
# Begin Whenever generated tasks for: RAILS_ENV=production
PATH=/home/admin/.rvm//gems/ruby-1.9.2-p180#admin/bin:/home/admin/.rvm//gems/ruby-1.9.2-p180#global/bin:/home/admin/.rvm//rubies/ruby-1.9.2-p180/bin:/home/admin/.rvm//bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
* * * * * cd /home/admin/releases/20120904103658 && RAILS_ENV=production rake db:populate:stocks --trace >> /home/admin/shared/log/cron.log 2>> /home/admin/shared/log/cron-error.log
THE PROBLEM is the cron task failed to execute the rake task, from cron-error.log :
/home/admin/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/site_ruby/1.9.1/rubygems.rb:314:in `bin_path': can't find gem rake ([">= 0"]) with executable rake (Gem::GemNotFoundException)
from /home/admin/.rvm//gems/ruby-1.9.2-p180#admin/bin/rake:19:in `<main>'
What i'm missing here, why the cron job failed to load my env ? Is there any problem with my schedule.rb ?
Make sure your RVM defaults to the correct ruby version where the gems are.
Then try to use bundle exec rake ...
by doing so it will explicitly invoke whatever the gems in the bundle (assuming you are using RVM)
I have similar problem and I fix with
rvm cron setup
in server. This add rvm env variables (PATH, GEM_HOME,GEM_PATH...) to my cronjob.
I have to delete the set command
env :PATH, ENV['PATH']
modifying PATH is not enough, check rvm help cron - there are few options that will help manage rvm in crontab.
I often used Rake tasks that are dependent upon the Rails environment task having loaded. I then interact with Rails Models within the Rake tasks. Can I do this in Capistrano?
You can definately use capistrano to fire a rake task.
desc 'Run a Rake Task.'
task :after_deploy, :roles => :app do
run "cd /path/to/app && rake -e environnment task here"
end
If you are asking if you can access a rails model from Capistrano, then I would say I don't think so unless you are using some other way that also loads a rails environment, like script/runner.
I'd say stick with firing a rake task from Capistrano.
The below might be better:
run "cd #{current_path} && #{rake} RAILS_ENV=#{rails_env} sunspot:solr:stop"