Skip Navigation
Show nav
Dev Center
  • Get Started
  • Documentation
  • Changelog
  • Search
  • Get Started
    • Node.js
    • Ruby on Rails
    • Ruby
    • Python
    • Java
    • PHP
    • Go
    • Scala
    • Clojure
    • .NET
  • Documentation
  • Changelog
  • More
    Additional Resources
    • Home
    • Elements
    • Products
    • Pricing
    • Careers
    • Help
    • Status
    • Events
    • Podcasts
    • Compliance Center
    Heroku Blog

    Heroku Blog

    Find out what's new with Heroku on our blog.

    Visit Blog
  • Log inorSign up
View categories

Categories

  • Heroku Architecture
    • Compute (Dynos)
      • Dyno Management
      • Dyno Concepts
      • Dyno Behavior
      • Dyno Reference
      • Dyno Troubleshooting
    • Stacks (operating system images)
    • Networking & DNS
    • Platform Policies
    • Platform Principles
  • Developer Tools
    • Command Line
    • Heroku VS Code Extension
  • Deployment
    • Deploying with Git
    • Deploying with Docker
    • Deployment Integrations
  • Continuous Delivery & Integration (Heroku Flow)
    • Continuous Integration
  • Language Support
    • Node.js
      • Working with Node.js
      • Node.js Behavior in Heroku
      • Troubleshooting Node.js Apps
    • Ruby
      • Rails Support
      • Working with Bundler
      • Working with Ruby
      • Ruby Behavior in Heroku
      • Troubleshooting Ruby Apps
    • Python
      • Working with Python
      • Background Jobs in Python
      • Python Behavior in Heroku
      • Working with Django
    • Java
      • Java Behavior in Heroku
      • Working with Java
      • Working with Maven
      • Working with Spring Boot
      • Troubleshooting Java Apps
    • PHP
      • PHP Behavior in Heroku
      • Working with PHP
    • Go
      • Go Dependency Management
    • Scala
    • Clojure
    • .NET
      • Working with .NET
  • Databases & Data Management
    • Heroku Postgres
      • Postgres Basics
      • Postgres Getting Started
      • Postgres Performance
      • Postgres Data Transfer & Preservation
      • Postgres Availability
      • Postgres Special Topics
      • Migrating to Heroku Postgres
    • Heroku Key-Value Store
    • Apache Kafka on Heroku
    • Other Data Stores
  • AI
    • Working with AI
    • Heroku Inference
      • Inference API
      • Quick Start Guides
      • AI Models
      • Inference Essentials
    • Vector Database
    • Model Context Protocol
  • Monitoring & Metrics
    • Logging
  • App Performance
  • Add-ons
    • All Add-ons
  • Collaboration
  • Security
    • App Security
    • Identities & Authentication
      • Single Sign-on (SSO)
    • Private Spaces
      • Infrastructure Networking
    • Compliance
  • Heroku Enterprise
    • Enterprise Accounts
    • Enterprise Teams
    • Heroku Connect (Salesforce sync)
      • Heroku Connect Administration
      • Heroku Connect Reference
      • Heroku Connect Troubleshooting
  • Patterns & Best Practices
  • Extending Heroku
    • Platform API
    • App Webhooks
    • Heroku Labs
    • Building Add-ons
      • Add-on Development Tasks
      • Add-on APIs
      • Add-on Guidelines & Requirements
    • Building CLI Plugins
    • Developing Buildpacks
    • Dev Center
  • Accounts & Billing
  • Troubleshooting & Support
  • Integrating with Salesforce
  • App Performance
  • Scheduled Jobs and Custom Clock Processes

Scheduled Jobs and Custom Clock Processes

English — 日本語に切り替える

Last updated October 16, 2024

Table of Contents

  • Overview
  • Simple job scheduling
  • Custom clock processes
  • Implementation

Many apps need to run jobs at scheduled times. For example, an app might need to poll a remote API every 5 minutes, or send an email report every night at midnight. The cron tool is commonly used for this use case, but it is ill-suited for horizontally scalable environments such as Heroku. A more powerful, flexible solution is a job scheduler.

See the simple job scheduling section for less demanding use-cases.

A job scheduler uses the process model to run a lightweight, singleton process that wakes up at a specified interval and schedules work to be performed. When paired with background workers, it forms a clean and extensible approach to job scheduling.

Overview

Scheduling a job and executing the job are independent tasks. Separating a job’s execution from its scheduling ensures that the responsibilities of each component are clearly defined, resulting in a more maintainable system.

Use a job scheduler only to queue background jobs, not to execute them. Background workers then independently receive and execute the queued jobs.

Scheduling background work

By decoupling your scheduling and execution components, you can easily scale your number of background workers to meet demand. For simplicity, do not scale your job scheduler beyond a single process if possible. Otherwise, you might schedule duplicate work unless you implement complicated locking logic.

Simple job scheduling

Apps with simple scheduling requirements (such as executing a task on a very coarse-grained interval (daily, hourly, or every 10 minutes) can use the Scheduler add-on as a job scheduler. This free tool usually suffices for simple recurring jobs.

Apps that define more specific execution intervals (such as three times a day, every two hours, or even every 5 seconds) instead need to implement a custom clock process to schedule jobs.

Custom clock processes

Beyond the ability to specify a custom schedule, a clock process has the additional benefit of being defined as part of the process model - consistent with other logical application components. This simplifies testing, reduces external dependencies and increases environment parity between development and production.

Defining custom clock processes

Custom clock implementations vary greatly by language. However, as part of an application’s process model, defining a clock process is very simple. Here is the Procfile for a typical Node.js application.

web:    node web.js
worker: node worker.js
clock:  node clock.js

Conceptually, the contents of clock.js are immaterial. What is important is that the clock.js process is responsible only for determining what jobs to run at what interval and for scheduling those jobs to be run in the background.

The background worker defined in worker.js is then responsible for receiving and immediately executing the scheduled work.

Clock processes on Heroku

As previously mentioned, the clock component should be a singleton process to avoid scheduling duplicate jobs and the need for complicated locking logic. Once deployed to Heroku simply scale the clock process to a single dyno.

$ heroku ps:scale clock=1
Scaling 'clock' processes... done, now running 1

The clock process needs to remain scaled up and running in order to determine suitable times to schedule a job. Billing hours accrue on the dyno as long as there is a running clock process, not just when it goes to schedule a job.

The worker process may need additional dynos if the scheduled jobs represent a material increase in processing. At the very least one worker dyno will need to be running to receive and execute scheduled jobs.

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.

Implementation

There are many libraries and services that allow you to implement scheduled jobs in your applications. For example, here’s how you can do it in Python.

Keep reading

  • App Performance

Feedback

Log in to submit feedback.

Worker Dynos, Background Jobs and Queueing Using Amazon CloudFront CDN

Information & Support

  • Getting Started
  • Documentation
  • Changelog
  • Compliance Center
  • Training & Education
  • Blog
  • Support Channels
  • Status

Language Reference

  • Node.js
  • Ruby
  • Java
  • PHP
  • Python
  • Go
  • Scala
  • Clojure
  • .NET

Other Resources

  • Careers
  • Elements
  • Products
  • Pricing
  • RSS
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku Blog
    • Heroku News Blog
    • Heroku Engineering Blog
  • Twitter
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku
    • Heroku Status
  • Github
  • LinkedIn
  • © 2025 Salesforce, Inc. All rights reserved. Various trademarks held by their respective owners. Salesforce Tower, 415 Mission Street, 3rd Floor, San Francisco, CA 94105, United States
  • heroku.com
  • Legal
  • Terms of Service
  • Privacy Information
  • Responsible Disclosure
  • Trust
  • Contact
  • Cookie Preferences
  • Your Privacy Choices