Rails - run a recurring activerecord command on schedule? - ruby-on-rails

Would appreciate any help getting started on writing a recurring task for a Rails console activerecord command line. I.e., at 11PM every night I would like to run the following command:
Store.all.map { |x| x.update_balance }
update_balance is a function within the Store model. Any pointers would be greatly appreciated, thank you!

Set up a rake task to do the job. Then, it's just a matter of calling the rake task from some sort of scheduling system.
If you're using a hosting service like Heroku, you will need to use their own scheduler. If not, you can do it in various ways, but the simplest (assuming you're on a linux/unix/ubuntu etc server) is to use cron, which is a built-in scheduler. See here: https://www.linux.com/learn/tutorials/420397:scheduling-magic-intro-to-cron-on-linux
One gotcha with cron is that it runs under it's own user account, rather than the one you log into the server with, which means it might not know about certain variables etc in your environment. This means that you will need to give it a bit of extra help, for example using the full path to things like bash, ruby and rake. Here's an example of a scheduled rake task from my cron list, which runs at 3am every day:
# m h dom mon dow command
0 3 * * * /bin/bash -c "source /etc/profile; cd /var/www/apps/myapp/www; /usr/local/bin/rake cached_data:update_all RAILS_ENV=production"

Related

Setting up a rake task with Resque Scheduler - Rails 4

I am on Rails 4 using the Resque Scheduler gem.
I am also using the sitemap generator gem in order to dynamically generate my sitemap.
I am having trouble figuring out the best way to schedule a rake task with resque scheduler. The sitemap generator recommends whenever, but I am assuming resque scheduler can accomplish the same thing (don't want to install another gem if I don't have to).
Does anyone know how to set this up?
I would like to run rake sitemap:refresh:no_ping every 5 hours.
I was thinking I would just schedule a background job and run it from there:
# resque_schedule.yml
update_sitemap:
every: 5h
class: "SitemapUpdater"
description: "This job refreshes the sitemap"
# sitemap_updater.rb
class SitemapUpdater
#queue = :sitemap_queue
def self.perform
# run rake task here
end
end
... however, I'm not sure if this is a good practice. Any advice would be much appreciated.
I don't see a problem with your approach, you just must be aware that the scheduler is reset during every deployment, so if you do frequent deploys, your scheduled jobs might be run later or even not run at all, as documented:
IMPORTANT: Rufus every syntax will calculate jobs scheduling time starting from the moment of deploy, resulting in resetting schedule time on every deploy, so it's probably a good idea to use it only for frequent jobs (like every 10-30 minutes), otherwise - when you use something like every 20h and deploy once-twice per day - it will schedule the job for 20 hours from deploy, resulting in a job to never be run.
You might also run the rake from system cron itself, which is an even more lightweight solution as it requires no scheduler gems at all, just the rake task, and will be scheduled reliably in time.
See e.g. this answer for setting up the "every 5 hours" frequency in crontab and you might also need to study RVM wrappers if you use RVM for your ruby project (you must call rake using the RVM wrappers in such case, e.g. call /home/deploy/.rvm/wrappers/ruby-2.3.0#mygemset/rake instead of just rake).

Running Rails Task From Cron

I have a Rails runner task that I want to run from cron, but of course cron runs as root and so the environment is set up improperly to get RVM to work properly. I've tried a number of things and none have worked thus far. The crontab entry is:
* 0 * * * root cd /home/deploy/rails_apps/supercharger/current/ && /usr/local/rvm/wrappers/ruby-1.9.3-p484/ruby bundle exec rails runner -e production "Charger.start"
Apologies for the super long command line. Anyhow, the error I'm getting from this is:
ruby: No such file or directory -- bundle (LoadError)
So ruby is being found in the RVM directory, but again, the environment is wrong.
I tried rvm alias delete [alias_name] and it seemed to do something, but darn if I know where the wrapper it generated went. I looked in /usr/local/rvm/wrappers and didn't see one with the name I had specified.
This seems like a common problem -- common enough that the whenever gem exists. The runner command I'm using is so simple, it seemed like a slam dunk to just put this entry in the crontab and go, but not so much...
Any help with this is appreciated.
It sounds like you could use a third-party tool to tether your Rails app to cron: Whenever. You already know about it, but it seems you never tried it. This gem includes a simple DSL that could be applied in your case like:
every :day # Or specify another period, or something else, see README
runner "Charger.start"
end
Once you've defined your schedule, you'll need to write it into crontab with whenever command line utility. See README file and whenever --help for details.
It should not cause any performance impact at runtime since all it does is conversion into crontab format upon deployment or explicit command. It's not needed, once the server is running, everything is done by cron after that.
If you don't want an extra gem anyway, you might as well check what command does it issue for executing your task. Still, an automated way of adding a cron task is easier to maintain and to deploy. Sure, just tossing a line into the crontab is easier — just for you and just this once. Then it starts to get repetitive and tiring, not to mention confusion for other potential developers who will have to set up something similar on their own machines.
You can run cron as different user than root. Even in your example the task begins with
* 0 * * * root cd
root is the user that runs the command. You can edit it with crontab -e -u username.
If you insist on running cron task as root or running as other user does not work for some reason, you can switch user with su. For example:
su - username -c "bundle exec rails runner -e production "Charger.start"

rake jobs:work issue in implementing projectfedena

I am trying to implement fedena v 2.3. [projectfedena.org] which is an opensource school management app. I have a problem with a feature of
the fedena.
When I try to send internal messages, either the recipient doesn't receive
the message or it doesn't appear in the Sent Box.
The same problem is discussed in the fedena forum
http://www.projectfedena.org/forum/9-support-and-troubleshooting/topics/724-internal-messaging-service-is-not-working
I have to run "rake jobs:work" again and again to see the output
When i executed the rake command it worked for me but the problem i dont know how to run it for everytime when it is needed.
The forum didn't give me a solution. I came across cron jobs, which runs
each and every minute which doesn't seem to be optimal solution.
You're probably using delayed_job in that project (I can't check it now, sadly github is down now) so you need to deamonize it instead of running it in foreground. How? Here's a great tutorial describing it, of course the easiest way of making delayed job run permanently would be to simply call on server:
rake jobs:work &
the & at the end will detach process from terminal and leave it running permanently, but that is not a very good way of resolving it, above link provides better approach.
Edit: GH is up now and i checked, indeed it is using delayed job so above link should help you.
I did this
crontab -u root -e
then type the following and save
* * * * * cd <rails_source_dir> && RAILS_ENV=production <rake path> jobs:work
rake path = "which rake"

A pulse or cron job for Rails app running in Heroku

I need some code executed once per day. Can be more than once a day and missing a day isn't the end of the world. That code will make sure users get some bonus points based on certain criteria. I'll keep track if they've already received the bonus points so it doesn't double up..
Some simple cron job calling a particular controller once in a while is perfect:
curl http://localhost/tasks/pulse
Of course a real crontab entry works great. Or is there an internal mechanism for this kind of thing in Rails? I'm using the latest stable Rails (currently 3.2.9).
The only wrinkle is this needs to work in Heroku too.
I just noticed Heroku's Scheduler. Looks great for Heroku. I can just run those tasks in my dev/test environment manually. Is this the best way to handle pulses/cron jobs in Rails? With rake tasks? Easy to incorporate running rake tasks in tests?
The Heroku Scheduler works great and is easy to set up!
You could check out this gem called whenever its a Ruby gem that provides a clear syntax for writing and deploying cron jobs. It's well maintained, not used it on Heroku myself but worth a look.
You can do loads of stuff like
every 3.hours do
runner "MyModel.some_process"
rake "my:rake:task"
command "/usr/bin/my_great_command"
end

How can I make sure the Sphinx daemon runs?

I'm working on setting up a production server using CentOS 5.3, Apache, and Phusion Passenger (mod_rails). I have an app that uses the Sphinx search engine and the Thinking Sphinx gem.
According to the Thinking Sphinx docs...
If you actually want to search against
the indexed data, then you’ll need
Sphinx’s searchd daemon to be running.
This can be controlled using the
following tasks:
rake thinking_sphinx:start
rake ts:start
rake thinking_sphinx:stop
rake ts:stop
What would be the best way to ensure that this takes place in production? I can deploy my app, then manually run rake thinking_sphinx:start, but I like to set things up so that if I have to bounce the server, everything will come back up.
Should I put a call to that Rake task in an initializer? Or something in rc.local?
rc.local is a good start, but its not enough. I would pair is with a monit rule to ensure it is running AND more importantly...
Sphinx requires a full-reindex to make all the latest and greatest available. There is some doco on the thinking sphinx site about delta indexing, but if your index is small, an hourly re-index will take care of things and you do not need the delta indexing stuff.
I run this hourly to take care of this:
0 * * * * cd /var/rails/my_site/current/ && RAILS_ENV=production /usr/bin/rake ts:rebuild
Note: for deployment, I will use the built in thinking sphinx capistrano tasks:
In your Capfile add
require 'thinking_sphinx/deploy/capistrano'
I used to chain the re-indexing in the cap task but stopped cause it is really slow, when I make schema changes I will remember to run it or wait for the hourly cron job to fix it up.
I haven't done this before with Spinix, so I hope someone can give you a better answer, but you should take a look at monit. Monit is designed for keeping daemons running, just like what you need to do.
A quick Google for spinix monit turned up this link: Capistrano recipes: sphinx:monit. That would be a good place to start.
For what it's worth, I'm running
thinking_sphinx:index
... in my cron job, instead of the "rebuild" task. This does not require the searchd process to be offline, but the indices are still rotated when it's done, so new changes are picked up. I think the "rebuild" task is only necessary when you actually change your index structure in your models, which happens very rarely for me.

Resources