Skip Navigation
Show nav
Heroku Dev Center
  • Get Started
  • Documentation
  • Changelog
  • Search
  • Get Started
    • Node.js
    • Ruby on Rails
    • Ruby
    • Python
    • Java
    • PHP
    • Go
    • Scala
    • Clojure
  • 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
    • Dynos (app containers)
    • Stacks (operating system images)
    • Networking & DNS
    • Platform Policies
    • Platform Principles
  • Command Line
  • Deployment
    • Deploying with Git
    • Deploying with Docker
    • Deployment Integrations
  • Continuous Delivery
    • Continuous Integration
  • Language Support
    • Node.js
    • Ruby
      • Working with Bundler
      • Rails Support
    • Python
      • Background Jobs in Python
      • Working with Django
    • Java
      • Working with Maven
      • Java Database Operations
      • Working with Spring Boot
      • Java Advanced Topics
    • PHP
    • Go
      • Go Dependency Management
    • Scala
    • Clojure
  • Databases & Data Management
    • Heroku Postgres
      • Postgres Basics
      • Postgres Getting Started
      • Postgres Performance
      • Postgres Data Transfer & Preservation
      • Postgres Availability
      • Postgres Special Topics
    • Heroku Data For Redis
    • Apache Kafka on Heroku
    • Other Data Stores
  • Monitoring & Metrics
    • Logging
  • App Performance
  • Add-ons
    • All Add-ons
  • Collaboration
  • Security
    • App Security
    • Identities & Authentication
    • Compliance
  • Heroku Enterprise
    • Private Spaces
      • Infrastructure Networking
    • Enterprise Accounts
    • Enterprise Teams
    • Heroku Connect (Salesforce sync)
      • Heroku Connect Administration
      • Heroku Connect Reference
      • Heroku Connect Troubleshooting
    • Single Sign-on (SSO)
  • 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
  • Continuous Delivery
  • Release Phase

Release Phase

English — 日本語に切り替える

Last updated February 06, 2023

Table of Contents

  • Specifying release phase tasks
  • When does the release command run?
  • Release command failure
  • Checking release status & logs
  • Canceling a release command
  • Review apps and the postdeploy script
  • Design considerations
  • Known issues

The release phase enables certain tasks to be run before a new release of an app is deployed. The release phase can be useful for tasks such as:

  • Sending CSS, JS, and other assets from the app’s slug to a CDN or S3 bucket
  • Priming or invalidating cache stores
  • Running database schema migrations

If a release phase task fails, the new release is not deployed, leaving the current release unaffected.

When using the release phase, there are a number of design considerations to take into account, especially if performing database migrations. The release phase has a 1-hour timeout, and this limit cannot be extended.

Specifying release phase tasks

To specify the tasks to run during the release phase, define a release process type in the app’s Procfile. For deploying Docker images to Heroku, learn more about using the release phase with Container Registry.

In this Procfile example, release executes a Django database migration:

release: python manage.py migrate
web: gunicorn myproject.wsgi

Whereas in this example, release runs a script that includes several different commands:

release: ./release-tasks.sh
web: gunicorn myproject.wsgi

When does the release command run?

The release command runs in a one-off dyno whenever a new release is created, unless the release is caused by changes to an add-on’s config vars. All of the following events create a new release:

  • A successful app build
  • A change to the value of a config var (unless the config var is associated with an add-on)
  • A pipeline promotion
  • A rollback
  • A release via the platform API
  • Provisioning a new add-on

App dynos do not boot for a new release until the release phase finishes successfully:

Release phase diagram

Use the heroku ps command to see your release command running.

The dyno type can be set using `heroku ps:type release={type}, but only after the release phase is run for the first time.

Release command failure

If the release command exits with a non-zero exit status, or if it’s shut down by the dyno manager, the release fails. In this case, the release is not deployed to the app’s dyno formation. An email notification is generated in the event of a release phase failure.

If a release is triggered by a change to the value of a config var, the config var value remains changed even if the release command fails.

It is possible for a build to succeed and its associated release to fail. This does not clear the build cache.

A failed release command usually requires a fix to an app’s code. After making the necessary changes, push the new code to trigger a new release.

In some cases, a release failure is unrelated to the app’s code. For example, an external service might be unavailable during the release phase. In such occurrences, the releases-retry CLI plugin can be used to retry a failed release without needing to trigger a new build on the app.

Checking release status & logs

To check on the status of a release, including failed releases and releases that are pending due to a long-running release command, run heroku releases.

$ heroku releases
=== limitless-savannah-19617 Releases - Current: v52
v53  Deploy ad7c527 release command failed        jbyrum@heroku.com
v52  Deploy b41eb7c                               jbyrum@heroku.com
v51  Deploy 38352d3                               jbyrum@heroku.com
...

Use the heroku releases:output command to see the output of a particular release command:

$ heroku releases:output RELEASE_NUMBER
--- Migrating db ---
INFO  [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO  [alembic.runtime.migration] Will assume transactional DDL.

Release logs are also available from the Heroku dashboard:

Screenshot of release logs

Checking release status programmatically

To check the status of a release programmatically, query the Platform API for a specific release or a list all releases (see Platform API documentation for more detail). In the following example using curl, the status key has a value of failed:

$ curl -n https://api.heroku.com/apps/<app_id_or_name>/releases/ \
          -H "Accept: application/vnd.heroku+json; version=3"
{
    "app":{
      "id":"a933b6af-b2e3-4a03-91a9-1c758110a553",
      "name":"limitless-savannah-19617"
    },
    "created_at":"2016-07-29T22:43:20Z",
    "description":"Deploy ad7c527",
    "status":"failed",
    "id":"735a9e8c-ef49-4047-8079-984d40a84051",
    "slug":{
      "id":"a49ed40f-801a-45ff-8b90-758c5a33637f"
    },
    "updated_at":"2016-07-29T22:43:20Z",
    "user":{
      "email":"jbyrum@heroku.com",
      "id":"cbcd34ce-c556-4289-8bc7-2dc160649fb7"
    },
    "version":53,
    "current":true,
    "output_stream_url":"https://release-output.heroku.com/streams/a9/..."
  }

The output of the release is available under the output_stream_url attribute and can be retrieved programmatically by making a GET request on the URL.

The output is sent via chunked encoding, and the connection is closed when the command completes.

If a client connects after data is sent for a given URL, the data is buffered from the start of the command. Output can be streamed while the command is in progress, and at any time after it has completed (in the latter case, all output will be sent immediately).

Canceling a release command

To cancel a release command, identify the one-off dyno executing the command:

$ heroku ps
=== release (Eco): bundle exec rake db:migrate
release.5129: up 2016/02/01 12:17:45 (~ 2s ago)

Then, provide the name of the one-off dyno to the heroku ps:stop command:

$ heroku ps:stop release.5129

Review apps and the postdeploy script

Review apps run the code in any GitHub pull request in a complete, disposable Heroku app. Review apps support a postdeploy script, which is used to run one-time setup tasks.

The following timeline illustrates the order of operations and a recommended division of tasks when using both the release phase and a postdeploy script for review apps.

With each new pull request, review app creation begins.

  • After a successful build, the release command runs. This is recommended for:
    • Database schema setup and migrations
    • CDN uploads
    • Cache invalidation and warmup
  • If release phase fails, review app creation also fails

After the release phase succeeds:

  • The postdeploy script runs. This is recommended for one-off tasks, such as:
    • Setting up OAuth clients and DNS
    • Loading seed or test data into the review app’s test database

On any subsequent changes to the pull request:

  • The release command runs again.
  • The postdeploy script does NOT run again. The postdeploy runs only once on creation of the review app.

The recommendations in this section also apply to Deploy to Heroku button apps that use a postdeploy script.

Design considerations

Minimize the amount of time a failed release is most recent

In the case where a build has succeeded, but the release phase failed, the built slug will be used by any later releases triggered by add-on config var changes. As those releases do not run the release phase, this can mean application code deploys without release phase tasks it depends on (database migrations, for example) being run. We recommend any release phase failures are resolved as soon as possible to avoid this (for example, by temporarily rolling back to a previous release).

Do not use the release phase for tasks requiring file system persistence

The release phase is not suitable for tasks that require filesystem persistence, as filesystem changes during the release phase will not be deployed to your app’s dyno formation (the dyno filesystem is ephemeral). For example, asset compilation should happen during builds. The release phase then can be used to upload the compiled assets to a CDN.

The following considerations are primarily relevant when creating manual database migration scripts. If using an ORM, such as ActiveRecord, these considerations may not apply. Learn more about database best practices.

Use transactions for database migrations

When performing a database migration, always use transactions. A transaction ensures that all migration operations are successful before committing changes to the database, minimizing the possibility of a failed partial migration during the release phase. If a database migration fails during the release phase (i.e., the migration command exits with a non-zero status), the new release will not be deployed. If transactions were not used, this could leave the database in a partially migrated state. We suggest using heroku run, rather than the release phase, to make schema/data corrections.

Check whether a database has already been migrated before executing a migration

Many actions create a new release, such as setting a config var or adding a new addon to the app. The database migration script should check whether a database has already been migrated before executing a new migration (e.g., does table/column exist, if not add it). Doing so will prevent a new release – such as one created from a new config var – from rerunning database migrations.

Before running a migration, grab an advisory lock on the database

Heroku releases can run concurrently, which can be a problem if the release phase is executing a database migration. Many popular relational databases, such as Postgres and MySQL, offer advisory lock functionality, which can be used to prevent concurrent migrations. Advisory locks are application enforced database locks; when acquired, the tables are not locked for writing, so the application will continue to behave normally.

Postgres makes it possible to acquire an advisory lock before running migrations. In the example below, we try to get an advisory lock with the key migration:

SELECT pg_try_advisory_lock(migration);

If the lock is successful, Postgres will return t. With a lock in place, it is now safe to run migrations. If unsuccessful, f is returned, instead, and migrations are safe to fail.

If the advisory lock is acquired within a transaction, it will be automatically released when the transaction is committed. Locks can be released manually using:

SELECT pg_advisory_unlock_all();

or

SELECT pg_advisory_unlock(key);

Ensure wrapped release phase tasks have their exit status properly rolled up

In the case of a release phase where multiple tasks are wrapped into a single file (e.g., release-tasks.sh), ensure each of those tasks has its exit status captured. If the captured status is not 0 (zero), the wrapper is responsible for adequately conveying it. Not capturing exit statuses for any wrapped commands will see their statuses swallowed, and the release phase will report as successful merely because of the successful invocation of release.sh.

A simple example of this behavior would look like:

# release-tasks.sh

## Step to execute
bundle exec rails db:migrate

# check for a good exit
if [ $? -ne 0 ]
then
  # something went wrong; convey that and exit
  exit 1
fi

# other code, potentially

Known issues

  • It is possible for a release command to fail due to an add-on not being fully provisioned when the command is run. For example, database migrations are triggered, but the database add-on isn’t finished with provisioning. This issue does NOT impact Heroku Postgres or Heroku Data for Redis.

Keep reading

  • Continuous Delivery

Feedback

Log in to submit feedback.

Review Apps (Old) Releases

Information & Support

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

Language Reference

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

Other Resources

  • Careers
  • Elements
  • Products
  • Pricing

Subscribe to our monthly newsletter

Your email address:

  • RSS
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku Blog
    • Heroku News Blog
    • Heroku Engineering Blog
  • Heroku Podcasts
  • Twitter
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku
    • Heroku Status
  • Facebook
  • Instagram
  • Github
  • LinkedIn
  • YouTube
Heroku is acompany

 © Salesforce.com

  • heroku.com
  • Terms of Service
  • Privacy
  • Cookies
  • Cookie Preferences