Whenever cron jobs fail to run - ruby-on-rails

I'm trying to use the whenever gem to run cron jobs into my application. I want to recalculate the attribute "value" of my model "User" every two minutes. Here are the steps I took:
Gemfile
gem 'whenever', :require => false
terminal
$ bundle install
$ wheneverize .
schedule.rb
every 2.minutes do
runner "User.recalculate"
end
models/user.rb
def self.recalculate
User.all.each {|user| user.recalculate_value }
end
private
def recalculate_value
self.value = self.value + 1
self.save!
end
terminal
$ whenever --update-crontab
and '$ whenever -l' returns this:
0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58 * * * * /bin/bash -l -c 'cd /home/website && bin/rails runner -e development '\''User:recalculate'\'''
But so far nothing has changed in my User.values. Running User.recalculate in my console works, so the error is apparently in Whenever. What am I missing?

I quickly created a new Rails app to try to reproduce your problem, you can find it here, clone it and see for yourself.
https://github.com/mlainez/stackoverflow-28111330/blob/master/app/models/user.rb
First thing you will want to do is verify what environment the runner is running in. By default, whenever uses production. If you're on your local machine, be sure to set it to development in your schedule.rb or check the documentation to see how to update the crontab and set the correct environment.
https://github.com/mlainez/stackoverflow-28111330/blob/master/config/schedule.rb#L7
This is what you should see in your crontab:
0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58 * * * * /bin/bash -l -c 'cd /Users/marc/Projects/stack && bin/rails runner -e development '\''User.recalculate'\'''
Notice it says rails runner -e development and not production.
Another thing is that basia was right. When I leave the private keyword and try to execute User.recalculate in rails c, it fails with:
private method `recalculate_value' called for #<User ...>
I'm surprised it works with the private keyword in your console... You are trying to access a private method on an instance. This is not possible in Ruby. You can only access public methods of an instance from the outside (unless you use send(:method)).
Removing the private keyword fixed it and the task ran as expected every two minutes.
I'm using Rails 4.2.0 and ruby 2.1.0 in my github code.
EDIT
Make sure your cron daemon is running using:
service cron status
I also noticed that in your crontab output you have:
bin/rails runner -e development '\''User:recalculate'\''
Notice the : between User and recalculate. You must have made a typo in your schedule.rb
It should be a . as it's a method call.
Also, you might wanna check that the output from whenever -l and crontab -l are the same. If crontab -l is different or empty, then you didn't use whenever --update-crontab or whenever -w correctly or something might be wrong with the whenever version you're using.

Remove private since right now running User.recalculate will fail with private method 'increment' called for #<User> error.
BTW, is User an ActiveRecord class? Cause there is increment http://apidock.com/rails/ActiveRecord/Base/increment method and increment! (saves record), so it might be good idea to change your method name to something else or just use user.increment!(:value).

You don't seem to be saving your user in your method increment. Try this:
def increment
self.value = self.value + 1
self.save
end

Related

Ruby on Rails - Whenever Gem + Cron Not Running

TL;DR: My Whenever Gem scheduled task does not run at all automatically but will manually.
I posted about this earlier in the week but got no responses, I'm attempting to implement the Whenever gem into my RoR 5 application. Once a year I want it to run a method in my 'User' model, but for testing purposes I have made it once every minute, like so:
Schedule.rb:
set :output, "/home/ubuntu/workspace/log/cron.log"
set :environment, 'development'
every 1.minute do
runner "User.(methodhere)"
end
User.rb:
def self.(methodhere)
User.all.each do |user|
user.update(remaining_days: user.total_days)
end
end
In multiple places I have read that sometimes cronjobs dont run properly in development mode, so I jumped through all of the hoops to put my application into production mode, and that did not help.
I then found that you can manually run these jobs in the command line, which I then tried to do using the command found doing:
whenever --update-cron
then
crontab -l
which showed
# Begin Whenever generated tasks for:
* * * * * /bin/bash -l -c 'cd /home/ubuntu/workspace && bundle exec
bin/rails runner -e development '\''User.new.(methodhere)'\'' >>
/home/ubuntu/workspace/log/cron.log 2>&1'
Running this manually:
/bin/bash -l -c 'cd /home/ubuntu/workspace && bundle exec
bin/rails runner -e development '\''User.(methodhere)'\'' >>
/home/ubuntu/workspace/log/cron.log 2>&1'
makes it work, and executes the (methodhere). Whenever just does not make it run automatically at the set interval.
Another thing I found was to try and restart cron, through cron restart, but I am receiving:
cron: can't open or create /var/run/crond.pid: Permission denied
I'm not sure if that has anything to do with the IDE I'm using, Cloud 9.
Many google searches have left me with nothing.
NOTE: I'm a very new developer with RoR, so any guidance on the matter would be greatly appreciated, thanks!

Whenever Gem - Undefined method '(methodhere)' for User(call 'User.connection' to establish a connection):Class

I'm attempting to implement the Whenever gem into my RoR 5 application. Once a year I want it to run a method in my 'User' model, but for testing purposes I have made it once every minute, like so:
Schedule.rb:
set :output, "/home/ubuntu/workspace/log/cron.log"
every 1.minute do
runner "User.(methodhere)"
end
User.rb:
def (methodhere)
User.all.each do |user|
user.update(remaining_days: user.total_days)
end
end
In multiple places I have read that sometimes cronjobs dont run properly in development mode, so I jumped through all of the hoops to put my application into production mode, and that did not help.
I then found that you can manually run these jobs in the command line, which I then tried to do using the command found doing:
whenever --update-cron
then
crontab -l
which showed
# Begin Whenever generated tasks for:
/home/ubuntu/workspace/config/schedule.rb
* * * * * /bin/bash -l -c 'cd /home/ubuntu/workspace && bundle exec bin/rails
runner -e production '\''User.year_days_reset'\'' >>
/home/ubuntu/workspace/log/cron.log 2>&1'
Running
/bin/bash -l -c 'cd /home/ubuntu/workspace && bundle exec bin/rails
runner -e production '\''User.(methodhere)'\'' >>
/home/ubuntu/workspace/log/cron.log 2>&1'
left me with an error in the log, like so:
Please specify a valid ruby command or the path of a script to run.
Run 'bin/rails runner -h' for help.
undefined method `(methodhere)' for User (call 'User.connection' to
establish a connection):Class
Many google searches have left me with nothing.
NOTE: Running my method (methodhere) manually in the rails console works perfectly as I want it to. I'm a very new developer with RoR, so any guidance on the matter would be greatly appreciated, thanks!
EDIT: #maxpleaner pointed out I was missing .new in User.new.(methodhere), which fixed the error, however I have a new issue. My code in schedule.rb seems to not be executing anything, as it is supposed to occur every minute but it is doing nothing.
You have to have an User class method
class User
def self.method
...
end
end
In that way you can use User.method in the schedule file.

Running a daily script affecting the database

I want to write a script that I can configure a cron to run every 24 hours beneath my Rails app.
script.rb
User.all.each do |user|
days = user[:days]
if days >= 1
days = days - 1
end
user.update_attribute(:days, days)
end
However, whenever I run this, I get this error:
uninitialized constant User (NameError)
What's going wrong?
If you are in Rails app's home directory, then simply:
rails runner -e production script.rb
For cron (suppose, script.rb is in home dir again):
Find out full path to your bundle (which bundle)
In your crontab add (change bundle and project paths accordingly):
0 * * * * cd /project_home && /bundle_executable exec rails runner -e production script.rb
Another approach is to require_relative 'config/environment.rb' (adjust paths to your use case) at the top of the script; There's a slight performance hit, but if you are only running this once a day, a few seconds of startup penalty won't matter.
Also, you may need to set RAILS_ENV appropriately to access the proper database tables.
I always use whenever to manage my cron jobs.
Install whenever, then add the following script to your config/schedule.rb:
every :day do
runner 'User.all.each {|user| user.decrement!(:days) if user.days > 0}'
end
Then run whenever -w from your terminal.

Cannot get whenever to run my rake task

I am trying to get whenever to run my rake task but it doesn't work.
#Command Line
$ whenever -w
[write] crontab file written
#schedule.rb
every :year, :at => "2014-07-25 17:39:48 -0700" do
rake 'timeperiod:create_timeperiod'
end
The rake command saves a model in the db and puts text so I would know if it worked (which it does when I run rake). Is there syntactically something wrong with what I did?
Note, the time and date in schedule.rb is arbitrary, I keep changing it to two minutes from now before testing.
Your task is probably failing because the shell used by cron is not the same you use with your normal user.
Check the log of the crontab:
grep CRON /var/log/syslog
Why don't you verify that your command is getting added to the crontab?
$ crontab -l
You can also add the job manually.
$ whenever
* * * * * * bash -l 'cd /path/to/dir; rake your:task'
$ crontab -e
# add the cron job
Also, output from cron jobs doesn't output to the screen; it goes to your mail. Check your mailbox.
From the man page:
When executing commands, any output is mailed to the owner of the
crontab (or to the user named in the MAILTO environment variable in
the crontab, if such exists). The children copies of cron running
these processes have their name coerced to uppercase, as will be seen
in the syslog and ps output.
For me, I'm using command but I think it's not the best case. Says my repo is in $HOME/www/virtualspirit, in my repository. So my whenever command will be cd /www/virtualspirit && /$HOME/.rvm/rubies/ruby-2.1.2/bin/rake timeperiod:create_timeperiod RAILS_ENV=production
double check it in crontab -e and see whether it saved.
There were a couple issues here.
The best way to add cron jobs to whenever is with the command whenever --update-crontab <name of identifier>
The format was incorrect. By specifying the time in cron directly, I was able to make it work.
For example:
#schedule.rb
every '13 15 26 7 *' do
rake 'timeperiod:create_timeperiod'
end

How to run a task rake on ruby on rails with a crontab ? (which works manually, without crontab)

i deployed (with capistrano) a ruby on rails project on an aws micro server.
I'm on ruby 1.9.2-290 and rails 3.2.6 and i also use bundler.
I developed a task rake in my opt/rails-project/lib/tasks/tasks.rake
namespace :myclass do
task "my-task" => :environment do
# do the stuff which work nicely if i enter my command line manually
end
end
This is how i call it in my crontab :
*/3 * * * * cd /opt/rails-project/current && /opt/rails-project/shared/bundle/ruby/1.9.1/gems/rake-0.9.2.2/bin/rake myclass:my-task RAILS_ENV=production >> ~/logs-my-task.txt
The file ~/logs-my-task.txt is created and updated every 3min as it does. This file only contains info of the version release from capistrano but nothing from my task rake.
As i said in my comment in my task rake, if i launch this command directly in the server via ssh, my task rake does its job...
I searched the web all day/night long and can not figure it out.
I tried to remove the http_basic auth from rails but same problem.
Hope you have a idea,
Thanks for help !
Try to put this part
cd /opt/rails-project/current && /opt/rails-project/shared/bundle/ruby/1.9.1/gems/rake-0.9.2.2/bin/rake myclass:my-task RAILS_ENV=production >> ~/logs-my-task.txt
inside some file, somescript.sh, give execution permissions:
chmod +x somescript.sh
and try to run it manually:
/path/to/somescript.sh
If it works, try to put it into crontab:
*/3 * * * * /path/to/somescript.sh
It often helps to put complex stuff inside script to run in from crontab.
Next step, ensure that you PATH environment variable the same for your shell and for cron. You can set it inside crontab or inside your script.
After I used a shell script as recommended by denis.peplin and launched it manually, I got the problem described here: Ruby on Rails and Rake problems: uninitialized constant Rake::DSL.
I included the following line in my Rakefile and let my crontab as it was before:
require 'rake/dsl_definition'

Resources