How can I get the heroku scheduler to run weekly?
Is this even possible, from what I can see I can only schedule hourly, every 10 mins, or daily tasks with no option for a weekly.
If not, what are other Heroku Add-ons that might allow me to run jobs (i.e. cron job) tasks on a weekly bassis in production.
Thanks!
Update 2:
require 'date'
task :weeklydelete do
if Date.today.wday.zero?
runner "Event.clear_expired"
runner "Activity.clear_expired"
end
end
Update 2.5:
$heroku run bundle exec rake weeklydelete -a friendiosenew
Running `bundle exec rake weeklydelete` attached to terminal... up, run.6194
rake aborted!
undefined local variable or method `path' for main:Object
/app/lib/tasks/weeklydelete.rake:2:in `block in <top (required)>'
Tasks: TOP => weeklydelete
(See full trace by running task with --trace)
I found a great answer here. Just use a bash script in the Heroku Scheduler that checks the day of the week before running your command:
if [ "$(date +%u)" = 1 ]; then MY_COMMAND; fi # only run on Mondays
Set up a daily job, and in the job check if the day of week is Sunday (or whichever day). If it is that day, run the job. If it isn't that day, do nothing and exit.
edit: I was thinking more like
require 'date'
task :weeklydelete do
if Date.today.wday.zero?
runner "Event.clear_expired"
runner "Activity.clear_expired"
end
end
The logging to a file stuff wont work on heroku, and I'm not sure what you're using for the time stuff, but I fear if scheduler runs it not exactly at 3, that stuff might not work.
the Date class has some really great helper methods. So, Date.today.wday.zero? could be shortened to Date.today.sunday?
The idea above about running a daily job but then having it exit without running if the day of the week isn't the day you want the job to run is a great solution. However, if you have a worker dyno running Sidekiq or DelayedJob (or any other queueing scheme that allows scheduled jobs), there's another solution, which is to seed the jobs queue with jobs that are not to be run until the day of the week you need.
This approach is a bit cleaner than checking for a particular day of the week, but it only makes sense if you are already using at least one background worker dyno and/or price sensitivity is not an issue.
Related
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).
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"
I have a task that takes over 45 minutes. It runs successfully with
$ heroku run rake:sales
I also doublechecked my settings in scheduler based on this question. Everything looks fine.
In order to prevent run-away jobs, jobs that run longer than their frequency will be terminated. For example, a job that runs every 10 minutes will be terminated after running for 10 minutes.
What's happening is that your rake task is running for the first 10 minutes, but Heroku aborts it after that elapses. They suggest using a background job queue for long-running tasks.
Source:
https://devcenter.heroku.com/articles/scheduler#long-running-jobs
Apart from the long-running issue that #KKobayashi has alluded to, you may not have the correct rake file created for the scheduler to run:
Heroku Scheduler:
For Rails, the convention is to set up rake tasks. To create your
scheduled tasks in Rails, copy the code below into
lib/tasks/scheduler.rake and customize it to fit your needs
Have you tried putting your tasks into a a scheduler.rake file?
It could be that you're scheduling the task for an app other than the one you intend to schedule it for.
To check, open the scheduler (heroku addons:open scheduler) and check the url. If you see another app's name in the url, you need to add the scheduler addon again i.e.:
heroku addons:create scheduler:standard
Now open it again (heroku addons:open scheduler)
Cronjob vs Scheduler for Heroku.
Sounds like you just need a periodic task to run once per day. The currently recommended way to do that at Heroku is to use the scheduler add-on:
Scheduler is an add-on for running jobs on your app at scheduled time intervals, much like cron in a traditional server environment.
A dashboard allows you to configure jobs to run every 10 minutes, every hour, or every day, at a specified time. When invoked, these jobs will run as one-off processes and show up in your logs as a process named run.N.
The basic process is pretty simple:
Set up a Rake task to do whatever it is you need to do:
desc "This task does ..."
task :your_task => :environment do
# Do something interesting...
end
Add the scheduler add-on in the usual manner:
$ heroku addons:add scheduler:standard
Then add your new Rake task through the Heroku dashboard.
If you want to run your periodic task outside Heroku then set up a cron job to run the appropriate Rake task.
You probably want to put this task into a Cron job which handles recurring processes or tasks.
Here is an excellent screencast on the subject courtesy of Ryan Bates:
http://railscasts.com/episodes/164-cron-in-ruby-revised
If you need to set up recurring jobs on Heroku, you need only add your tasks to lib/tasks/scheduler.rake and configure them using the Schedular Add-on
http://devcenter.heroku.com/articles/scheduler
I created an app that uses the whenever gem. The gem creates cron jobs. I got it working locally but can't seem to get it working on heroku cedar. What's the command to do this?
running:
heroku run whenever --update-crontab job1
doesn't work
Short answer: use the scheduler add-on: http://addons.heroku.com/scheduler
Long answer: When you do heroku run, we
spin up a dyno
put your code on it
execute your command, wait for it to finish
throw the dyno away
Any changes you made to crontab would be immediately thrown away. Everything is ephemeral, you cannot edit files on heroku, just push new code.
You need to add Heroku Scheduler addon.
You can add it directly from your dashboard or using following commands:
install the add-on:
heroku addons:create scheduler:standard
Create a rake task in lib/tasks
# lib/tasks/scheduler.rake
task :send_reminders => :environment do
User.send_reminders
end
Schedule job
Visit Heroku Dashboard
Open your app
Select Scheduler from add-ons list
Click Add Job, enter a task and select frequency.
e.g. Add rake send_reminders, select "Daily" and "00:00" to send reminders every day at midnight.
The other answers specify you should use the Heroku Scheduler add-on, and it is able to run a background tasks indeed, but it doesn't support the flexibility of cron.
There's another add-on, called Cron To Go, that is able to run your jobs on one-off dynos with cron's flexibility. You can also specify a timezone for your job and get notifications (email or webhook) when job fail, succeed or start.
(Full disclosure - I work for the company that created and operates Cron To Go)
If you want to:
Use Heroku Scheduler
Run tasks every minute (not 10 min)
Don't care about dyno hours
This was my solution hack to run jobs every minute - assuming the task completes in under 60 seconds.
task start_my_service: :environment do
1.upto(9) do |iteration|
start_time = DateTime.now
Services::MyService.call
end_time = DateTime.now
wait_time = 60 - ((end_time - start_time) * 24 * 60 * 60).to_i
sleep wait_time if wait_time > 0
end
end
Heroku doesn't support cron jobs. And there are two drawbacks to the Heroku Scheduler :
you cannot choose an arbitrary interval or time at which to run jobs (it's either every 10 mins, 1 hour or daily).
your jobs are not defined in code, hence not in your versioning system and not easy to keep track of or modify.
Heroku does provide an alternative : custom clock processes. But the clock process requires its own dyno, and "Since dynos are restarted at least once a day some logic will need to exist on startup of the clock process to ensure that a job interval wasn’t skipped during the dyno restart".
Simple scheduler is a gem made specifically made for scheduling on Heroku, but seems a bit hackish.
I ended up using sidekiq-cron. Only drawback : if sidekiq is down right when a job is scheduled to run, the job won't run.