This add-on is operated by MISC CO BV
Reliable and powerful task scheduling as a service.
Advanced Scheduler
Last updated June 23, 2024
Table of Contents
- Provisioning the add-on
- Defining tasks
- Testing tasks
- Scheduling tasks
- Debugging tasks
- Long-running tasks
- Dyno Type
- Concurrent one-off dyno limits
- Dashboard
- Service API
- Heroku CLI Plugin
- Task monitoring
- Tasks timing out
- Import Heroku Scheduler Jobs
- Advanced Scheduler and Container Registry
- Migrating between plans
- Removing the add-on
- Support
Advanced Scheduler is an add-on that provides task scheduling as a service on Heroku using one-off dynos and cron expressions.
The service is built on the same principles as Heroku Scheduler, and it distinguishes itself by providing greater flexibility, transparency, and reliability in a cost-effective way.
All features are accessible from the Advanced Scheduler dashboard. It allows you to configure triggers that execute your tasks once on a specific date and time, or at a certain time interval. When executed, these tasks run in one-off dynos and show up in your application’s logs. This service is language-agnostic, meaning it can be integrated regardless of the programming language you use.
Like Heroku Scheduler, Advanced Scheduler executes scheduled tasks via one-off dynos that will count towards your monthly usage.
Advanced Scheduler depends on the Heroku Platform API for task execution. If the API is unavailable, execution of your scheduled tasks can be missed. If scheduled tasks are a critical component of your application, it is recommended to run a custom clock process instead.
Provisioning the add-on
Advanced Scheduler can be attached to a Heroku application via the CLI:
A list of all plans available can be found here.
$ heroku addons:create advanced-scheduler
-----> Adding advanced-scheduler to sharp-mountain-4005... done, v18 (free)
After you install Advanced Scheduler, your application should be configured to fully integrate with the add-on. If you are new to task scheduling, you can read up on defining, testing, scheduling and debugging tasks below.
Defining tasks
Tasks are any command that can be run in your application.
Almost every framework or language has a convention to define such a command. Some have a built-in feature for setting up tasks, while others require you to add a script to bin/
that will perform the task.
Note that each framework or language might define tasks in a different way. Refer to the best practices for the framework or language you are using inside your application.
For Rails, the convention is to set up rake tasks. To create your task 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 Advanced Scheduler 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
An example bin/clean-sessions
script:
#!/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."
Note that if you are using a script, an interpreter might be needed in the command above to execute your task correctly. To prevent this, add a shebang at the top of your script (e.g., #!/usr/bin/env node
for Node.js or #!/usr/bin/env ruby
for Ruby). This tells the system which interpreter to use to execute the script.
Testing tasks
Once you have written your task and see that it 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 <your-task>
Scheduling tasks
To schedule a task, you need to create a new active trigger for it. Triggers are configured using the Advanced Scheduler dashboard.
Enter the task and specify if the trigger needs to be executed only once or at a certain time interval. For one-off triggers, define a date and time at which the task should be executed. For recurring triggers, provide a standard cron expression or use the schedule helper to define the interval. As a tip, check your cron expressions here to verify they are correct. By default, a new trigger will be activated directly after creation. If you do not want this behaviour, you can configure the trigger to stay inactive.
Instead of specifying a command, you can specify one of the process types in your app’s Procfile. 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.
Note that for each plan there are limits on the total number of tasks that can be scheduled at one point in time, as well as the total number of task executions in one month. Once one of these limits is exceeded, attempts to schedule a new task will fail.
Debugging tasks
To debug a task, you have to check your application’s logs. You can check your logs in real time or use any of the logging add-ons available in the Heroku Marketplace.
To check your real-time logs, use the heroku logs
command:
$ heroku logs -t -a <your-app> -d advanced-scheduler
2020-01-15T14:10:16+00:00 heroku[advanced-scheduler.1]: State changed from created to starting
2020-01-15T14:10:16+00:00 app[advanced-scheduler.1]: Starting process with command `node bin/send-newsletter.js`
2020-01-15T14:10:19+00:00 app[advanced-scheduler.1]: Sending newsletters...
2020-01-15T14:10:27+00:00 app[advanced-scheduler.1]: done.
2020-01-15T14:10:28+00:00 heroku[advanced-scheduler.1]: State changed from up to complete
A running task is also visible with the heroku ps
command:
$ heroku ps
=== advanced-scheduler (Free): node bin/send-newsletter.js (1)
advanced-scheduler.1: up 2020/01/15 14:10:16 +0100 (~ 2s ago)
The task monitoring of Advanced Scheduler depends on the result of your task. Make sure your task exits with the right exit code (sometimes referred to as a return status or exit status). A successful task returns a 0, while an unsuccessful one returns a non-zero value.
Long-running tasks
Although it is generally recommended to keep tasks lightweight and quick to execute, Advanced Scheduler can be used for longer-running tasks. Make sure to only have 1 task running by setting the execution interval higher than the task’s maximum execution time. In the event that a specific task does run longer than intended, you can force the task to exit by setting its trigger’s timeout value to the maximum allowed execution time. See tasks timing out to learn more.
Note that a task can run for up to 24 hours by settings its trigger’s timeout value to 86400 seconds.
Dyno Type
When configuring a trigger, select a dyno type available within the dyno tier configured for your Heroku app. In other words, you can only use for example standard-2x
for your one-off dynos when you use the Professional tier for your formation dynos.
Heroku offers the following dyno tiers:
- Eco tier: An app that uses
eco
dynos can only useeco
dynos for its one-off dynos. - Basic tier: An app that uses
basic
dynos can only usebasic
dynos for its one-off dynos. - Professional tier: An app that uses Professional-tier dynos (
standard
andperformance
) can usestandard-1x
,standard-2x
,performance-m
,performance-l
,performance-l-ram
,performance-xl
andperformance-2xl
for its one-off dynos. - Private tier: An app that uses Private-tier dynos can use
private-s
,private-m
,private-l
,private-l-ram
,private-xl
andprivate-2xl
for its one-off dynos. - Shield tier: An app that uses Shield-tier dynos can use
shield-s
,shield-m
,shield-l
,shield-l-ram
,shield-xl
andshield-2xl
for its one-off dynos.
When a trigger is configured to use a type of dyno that is not available for your Heroku app, Advanced Scheduler will automatically fall back to Heroku’s default dyno type for your app.
Concurrent one-off dyno limits
The limit for your app’s concurrently running one-off dynos depends on several factors. See which limit applies to your situation.
Beware that when exceeding your app’s concurrent one-off dyno limit, the next task might not be executed.
To stay below Heroku’s concurrent one-off dyno limit, make sure to plan the execution of your tasks with care. Avoid a backlog of one-off dynos created when scheduled tasks are executed before running tasks are finished or time out.
Alternatively, you can contact Heroku to get your limit raised.
Dashboard
The Advanced Scheduler dashboard allows you to configure one-off and recurring triggers that execute different tasks.
You can access the dashboard via the CLI:
$ heroku addons:open advanced-scheduler
Opening advanced-scheduler for sharp-mountain-4005
or by visiting the Heroku Dashboard and selecting the application in question. Select Advanced Scheduler from the Add-ons menu.
Service API
The Advanced Scheduler Service API lets you programmatically automate, extend and combine Advanced Scheduler with other services. You can use the Service API to create and manage triggers. For details, see the Service API Reference.
To interact with the Service API, you will need an API token. This API token can be generated in the Advanced Scheduler dashboard.
Note that when generating an API token in the Advanced Scheduler dashboard, the ADVANCED_SCHEDULER_API_TOKEN
config var will be set on your Heroku application and cause it to restart.
Heroku CLI Plugin
Advanced Scheduler provides an Heroku CLI plugin to create and manage triggers directly from the terminal using the Heroku CLI. For details, see the Advanced Scheduler CLI Reference.
To install the plugin:
$ heroku plugins:install advanced-scheduler
To start using the plugin:
$ heroku triggers --app example
=== 01234567-89ab-cdef-0123-456789abcdef (active): Monday morning newsletter
At 09:00 AM, only on Monday (UTC) w/ Standard-1X ⬢
$ node bin/send-newsletter.js
To consult the plugin documentation:
$ heroku triggers -h
List the Advanced Scheduler triggers for an app
USAGE
$ heroku triggers...
OPTIONS
-a, --app=app (required) app to run command against
-h, --help show CLI help
-j, --json output triggers in json format
EXAMPLE
$ heroku triggers -a example
COMMANDS
triggers:activate Activate an Advanced Scheduler trigger for an app
triggers:create Create a new Advanced Scheduler trigger for an app
triggers:deactivate Deactivate an Advanced Scheduler trigger for an app
triggers:delete Permanently delete an Advanced Scheduler trigger for an app
triggers:update Update an Advanced Scheduler trigger for an app
Task monitoring
By default, Advanced Scheduler monitors the executions of your scheduled tasks. For every trigger an email notification is sent on the first failed execution each day.
Note that the successful or failed execution of your task depends on the process exit code (sometimes referred to as a return status or exit status), so make sure your process is exiting properly. When the process exits with code 0, the execution is considered successful. Anything else is treated as a failed execution.
Whenever a one-off dyno fails to be provisioned, the process never actually runs and consequently there is no process exit code. Advanced Scheduler interprets this as a failed execution and sends a task failure alert notification with exit status null
.
Alert Notification Subscribers
By default, the distribution for email notifications is to all app owners and collaborators for non-org accounts, and admins for people in a Heroku Enterprise org. Alternatively, reach out to support@advancedscheduler.io to add additional email addresses, such as for email-based PagerDuty integration.
Tasks timing out
When a task runs longer than its trigger’s timeout value, it will be forced to exit shortly after. This mechanism is intended to either prevent a backlog of one-off dynos or to ensure only 1 task of a specific trigger is running at a time. Always aim to make tasks finish by themselves. When a task does time out, make sure to figure out why and take action to prevent it from happening again.
Advanced Scheduler supports getting alert notifications on task timeout. Opt-in by reaching out to support@advancedscheduler.io.
Note that the default timeout value for new triggers is 1800 seconds or 30 minutes and the maximum timeout value is 86400 seconds or 24 hours.
Import Heroku Scheduler Jobs
Heroku Scheduler jobs can be imported into Advanced Scheduler using the Advanced Scheduler dashboard. Advanced Scheduler is totally compatible with Heroku Scheduler. All imported jobs will behave exactly the same after import.
To start importing your Heroku Scheduler jobs, head to the Advanced Scheduler dashboard and click the Import Heroku Scheduler Jobs
button in the Triggers section of the overview page.
All imported jobs will be inactive to avoid collisions with your existing Heroku Scheduler jobs.
Heroku API token
Advanced Scheduler uses a Heroku API token to access the Heroku Scheduler jobs on your Heroku app. The Heroku API token can be retrieved using the heroku auth:token
command, which outputs your current Heroku CLI authentication token and when it will expire. The token can be explicitly invalidated by running heroku auth:logout
. For more information check out the Heroku CLI documentation.
The provided Heroku API token will not be stored by Advanced Scheduler and will only be used to perform a single GET request to fetch your Heroku Scheduler jobs.
Heroku Scheduler Timeouts
All jobs run by Heroku Scheduler have a maximum runtime equal to the frequency of their execution. For example, jobs scheduled to run every 10 minutes will be terminated after approximately 10 minutes. To make sure imported jobs behave identically, Advanced Scheduler uses the same timeout values that Heroku Scheduler uses.
Advanced Scheduler and Container Registry
If you are using Advanced 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.
Migrating between plans
Note that application owners should carefully manage the migration timing to ensure proper application function during the migration process.
Use the heroku addons:upgrade
command to migrate to a new plan.
$ heroku addons:upgrade advanced-scheduler:newplan
-----> Upgrading advanced-scheduler:newplan to sharp-mountain-4005... done, v18 ($49/mo)
Your plan has been updated to: advanced-scheduler:newplan
When downgrading to a plan that does not include access to the Advanced Scheduler Service API, the API token will be removed if applicable. This action will also remove the config var ADVANCED_SCHEDULER_API_TOKEN
and cause your Heroku application to restart.
Removing the add-on
You can remove Advanced Scheduler via the CLI:
This will destroy all associated data and cannot be undone!
$ heroku addons:destroy advanced-scheduler
-----> Removing advanced-scheduler from sharp-mountain-4005... done, v20 (free)
Support
All Advanced Scheduler support and runtime issues should be submitted via one of the Heroku Support channels. Any non-support related issues or product feedback is welcome at support@advancedscheduler.io.