Heroku is an App Engine for Ruby on Rails … and other Languages and Frameworks. Heroku is running your application and you don’t have to care about hardware or IT-Infrastructure. It is one abstraction layer above the Amazon Cloud EC2.
First of all, there are no cron jobs on Heroku. Because it is an App Engine you don’t have access to the linux os and the native cron daemon or crontab. Forget it! You have to use heroku worker dynos. Keep reading.
Usually you push your rails app via git to Heroku like this:
git push heroku master
and then it will be deployed on x web dynos. There are different kind of dynos. The default is “web”. If you want to do some background jobs you need a “worker” dyno. You can add worker dynos with this command:
heroku ps:scale worker=1
Now you have to create a Procfile in the root of your application. That can look like this:
web: bundle exec rails server -p $PORT worker: bundle exec rake do_work
The Procfile is defining the different types of dynos which are available for your application. With “heroku ps:scale” you can scale the dyno types. If you want to have 7 web dynos and 1 worker just execute this:
heroku ps:scale web=7 worker=1
And Heroku will immediately deploy your web application on 7 web dynos and your background job on 1 worker dyno. That is fucking awesome!
All right we added one worker dyno and we defined in the Procfile that “bundle exec rake do_work” should be executed on the worker dyno. Now we just have to define the task “do_work” in the Rakefile.
There are different GEMs for scheduling jobs. For example clockwork, rufus and Qu. I prefer a more simple/native way. With a couple lines of code you can write your own scheduler. This rake task here is executing jobs at a given time. In this example every day at 07:00 AM.
task :do_work => :environment do puts "START" start_hour = 7 start_minute = 0 until 2 < 1 do now = Time.now hour = now.hour minute = now.min if hour == start_hour && minute == start_minute puts " do work #{Time.now}" # execute code here !!! if Time.now.hour == start_hour && Time.now.min == start_minute sleep(60) end end end end
Just replace the comment with your code. And push it to heroku
heroku maintenance:on git push heroku master heroku maintenance:off
That’s it.