Last updated February 06, 2023
Table of Contents
Scheduler is a free add-on for running jobs on your app at scheduled time intervals, much like
cron in a traditional server environment.
While Scheduler is a free add-on, it executes scheduled jobs via one-off dynos that will count towards your monthly usage.
Scheduler job execution is expected but not guaranteed. Scheduler is known to occasionally (but rarely) miss the execution of scheduled jobs. If scheduled jobs are a critical component of your application, it is recommended to run a custom clock process instead for more reliability, control, and visibility.
Once you access its interface, a dashboard will allow 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 dynos and show up in your logs as a dyno named like
Installing the add-on
Using the CLI
$ heroku addons:create scheduler:standard
Using the Dashboard
Navigate to the “Resources” tab of the app’s Dashboard. Search for “Heroku Scheduler” in the Add-ons search box. Follow the prompts to provision the Add-on.
Dyno hour costs
Scheduler runs one-off dynos that will count towards your usage for the month. Dyno-hours from Scheduler tasks are counted just like those from
heroku run or from scaled dynos. They will appear with a “scheduler” dyno type in your Heroku invoice.
Tasks are any command that can be run in your application.
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.
desc "This task is called by the Heroku scheduler add-on" task :update_feed => :environment do puts "Updating feed..." NewsFeed.update puts "done." end task :send_reminders => :environment do User.send_reminders end
For apps built on other frameworks or languages, another convention is to add a script to bin/ that will perform the task. An example
#!/usr/bin/env ruby require "sequel" DB = Sequel.connect ENV["DATABASE_URL"] puts "Cleaning old sessions..." DB["DELETE FROM sessions WHERE last_seen_at < ?", Time.now - 24*60*60] puts "done."
Once you’ve written your task and see that is functioning locally, the next step is to deploy your application and test your task on Heroku. To do so, use
heroku run to run your task on Heroku:
$ heroku run rake update_feed
The scheduler uses the same one-off dynos that
heroku run uses to execute your jobs, so you can be assured that if it works with
heroku run, it will work from the scheduler.
To schedule a frequency and time for a job, open the Scheduler dashboard by finding the app in My Apps, clicking “General Info”, then selecting “Scheduler” from the Add-ons drop down. The dashboard can also be opened from the command:
$ heroku addons:open scheduler
On the Scheduler Dashboard, click “Add Job…”, enter a task, select a frequency, dyno size, and next run time.
Note that the next run time for daily jobs is in UTC. If you want to schedule the job at a certain local time, add the proper UTC offset.
For example, add
rake update_feed, select “Hourly” and “:30” to update feeds every hour on the half-hour. Then add
rake send_reminders, select “Daily” and “00:00” to send reminders every day at midnight.
Instead of specifying the command, you can specify a process type. The command associated with the process type will then be executed, together with any parameters you supply. See the syntax for one-off dynos to learn more.
Logs for scheduled jobs go into your logs as process
$ heroku logs --ps scheduler.1 2011-02-04T14:10:16-08:00 heroku[scheduler.1]: State changed from created to starting 2011-02-04T14:10:16-08:00 app[scheduler.1]: Starting process with command `bin/clean_sessions` 2011-02-04T14:10:19-08:00 app[scheduler.1]: Deleting stale sessions... 2011-02-04T14:10:27-08:00 app[scheduler.1]: done. 2011-02-04T14:10:28-08:00 heroku[scheduler.1]: State changed from up to complete
The scheduled dyno is also visible with the
heroku ps command:
$ heroku ps === scheduler: `bin/clean_sessions` scheduler.1: complete for 5m === web: `bundle exec thin start -p $PORT -e production` web.1: idle for 3h
Scheduled jobs are meant to execute short running tasks or enqueue longer running tasks into a background job queue. Anything that takes longer than a couple of minutes to complete should use a worker dyno to run.
A dyno started by scheduler will not run longer than its scheduling interval. For example, for a job that runs every 10 minutes, dynos will be terminated after running for approximately 10 minutes.
Note that there is some jitter in the dyno termination scheduling. This means that two dynos running the same job may overlap for a brief time when a new one is started.
Known issues and alternatives
Scheduler is a free add-on
Scheduler is a free add-on with no guarantee that jobs will execute at their scheduled time, or at all:
- In very rare instances, a job may be skipped.
- In very rare instances, a job may run twice.
Heroku Scheduler and Container Registry
If you are using Heroku Scheduler and Container Registry as your deployment method, your task must be accessible from the
web image. There is no way to specify a non-web image for task execution.
Alternatives to Heroku Scheduler
An alternative to Heroku Scheduler is to run your own custom clock process. This provides greater control and visibility into process scheduling, and is recommended in production deployments in which scheduled jobs are a critical component. Please see this article for more information.
The Dynos category In the Elements Marketplace has several add-on solutions for scheduling tasks and running processes on your behalf.