68

This terminal command restarts my heroku application:

heroku restart

Is there a way to run a script that will run this command and restart my application every hour?

Matteo Alessani
  • 10,264
  • 4
  • 40
  • 57
Oded Harth
  • 4,367
  • 9
  • 35
  • 62
  • I have a need for the same thing. My reason is that I am updating I18n translations on cron, and need to restart the app to flush the I18n cache. – Matthew Rudy Jan 31 '12 at 07:40
  • @Oded you should pick an answer, please, so that people don't keep seeing this in their feeds of "unanswered". Thanks! – WattsInABox Oct 08 '14 at 16:10

8 Answers8

36

I actually just had to solve this problem for my apps and wrote a post on it with more details. Basically, you need the heroku-api gem now since the heroku gem is replaced by the CLI. Then you need a rake task, a couple of config variables and the heroku scheduler plugin (free except for minimal dyno time).

The rake task looks like this:

namespace :heroku do
  desc 'restarts all the heroku dynos so we can control when they restart'
  task :restart do
    Heroku::API.
      new(username: ENV['HEROKU_USERNAME'], password: ENV['HEROKU_PASSWORD']).
      post_ps_restart(ENV['HEROKU_APP_NAME'])
  end
end

You can also set it up to use your API token instead of putting your username and password into the config. This only matters if you don't want your co-contributors/coworkers knowing your password or the password to your main account on Heroku.

heroku config:set HEROKU_USERNAME=[username] HEROKU_PASSWORD=[password] HEROKU_APP_NAME=[app_name] -a [app_name]

Now, go ahead and deploy and test:

git push [heroku_remote_name] [feature_branch]:master
heroku run rake heroku:restart -a [app_name]

Lastly, we’ll need to set up the task to run this on schedule. I’ve chosen to go with the free Heroku cron add-on:

heroku addons:add scheduler:standard -a [app_name]
heroku addons:open scheduler -a [app_name]

This will open up the scheduler UI in your browser and you can create a scheduled worker to run the rake task whenever you’d like. We only need it once per day and we’re choosing to run it before our first scheduled job of the day.

My original post with frigged up CSS (see update2 below):

https://web.archive.org/web/20150612091315/http://engineering.korrelate.com/2013/08/21/restart-heroku-dynos-on-your-terms/

UPDATE

I changed the name of the task from "implode" to "restart" to be way more clear as to what is happening. Implode is a fun name but pretty much useless otherwise.

UPDATE2

Apparently my company removed the blog post. I'm adding more of the code here and I've updated the link, but the CSS looks like a dog threw it up. My apologies.

WattsInABox
  • 4,548
  • 2
  • 33
  • 43
  • 1
    Here is a ready-to-deploy rake task based on your solution: https://github.com/demental/herokustarter . The reason why I needed this was because I had to clear some memoization from outside the application (I18n ActiveRecord Backend). I can't see any other way. – demental Sep 18 '14 at 21:20
  • 1
    site not found error on opening the link. Can you update the link – coderVishal Jan 10 '16 at 14:40
  • Sorry if I have missed this, but could someone let me know the format of username and app name here? Is it username = email address and app-name= appname.com or appname.herokuapp.com? – Ryan Murphy Mar 08 '17 at 02:19
  • I didn't post that stuff, Ryan, you didn't miss it. I assumed people knew how to use heroku CLI. `-a my_app` is the format for the app. Usernames are not how the CLI works. You need authorization through `heroku auth` by giving heroku your public key and having someone add you to the app in the heroku UI. – WattsInABox Mar 20 '17 at 16:36
14

You could create a heroku cron job that uses the Heroku api on your application to restart itself...

One question though - why?

John Beynon
  • 37,398
  • 8
  • 88
  • 97
  • 12
    I have a memory leak in my application, and restarting the application resets the memory usage. So this could be a temporary fix until we'll fix the memory problem. – Oded Harth Jan 24 '12 at 12:14
  • 3
    beside of cron add-on u can make a cron from ur local system or any other server (that is live with internet) to run the "heroku restart" hourly. – Gul Jan 24 '12 at 14:53
  • 1
    The main reason I think to have something like this is heroku restarts each dyno 24 hours after it was brought up. This will pretty much be a random time if you do nothing. If instead you restart your application at your own time during some low-traffic time, you can minimize the impact to your business. The OP says "every hour" but these solutions can be adapted for any restart timeframe. – WattsInABox Apr 19 '17 at 16:05
9

A script isn't necessary, just "crash" your application and Heroku will restart it.

Just don't do this more frequently than once every ten minutes or Heroku will subject you to a 10 minute timeout.

In node.js you do this with process.exit(0).

From Chris at Heroku Support:

A crashed dyno will be restarted immediately. If the dyno moves from a crashed state into an "up" state (meaning that the dyno bound to $PORT) then it's subject to being a normal running dyno. If it crashes again during the boot or "starting" sequence then it won't be restarted again until after the TIMEOUT period. The TIMEOUT period is currently 10 minutes but that is subject to change. This prevents dynos that are continually crashing from putting extraneous load on the platform.

However, as good as that sounds, it doesn't work in practice. You will hit the timeout every time you exit because the dyno manager expects your app to be up:

For your worker process management you're exiting the process cleanly but the platform is expecting the dyno to be up. It sounds like you're essentially crashing the dyno as a result.

So again, if you need to restart periodically -- and that period can be set to > 10 minutes -- this is a easy and simple way to manage memory clearing. If you need to reboot dynamically (for example, when idle is detected) or frequently you will need to explore other options.

You can access the name of the dyno (ex. "worker.3", "web.1") through the environment variable "PS" and issue a heroku API restart command programmatically.

DrFriedParts
  • 469
  • 10
  • 18
  • 3
    This is necessary for some, in our case, our app takes 80 seconds to boot on heroku and when they do their automated daily dyno cylces it causes timeout errors for users. If we do a heroku restart, it utilizes preboot, and the dynos are up before they get traffic. – Troy Anderson Mar 31 '14 at 16:53
  • 1
    This solution works very well for ruby on rails apps. Simply schedule a task that runs a single command `exit` and that's it! – stevec Dec 24 '18 at 01:01
9

We solved this by using a buildpack to get the heroku command available to the dyno itself, then using Heroku Scheduler.

We added the https://github.com/gregburek/heroku-buildpack-toolbelt buildpack per its instructions:

heroku buildpacks:add https://github.com/gregburek/heroku-buildpack-toolbelt.git
heroku config:add HEROKU_TOOLBELT_API_EMAIL=`heroku whoami`
heroku config:add HEROKU_TOOLBELT_API_PASSWORD=`heroku auth:token`

Then made sure the app slug was rebuilt per the instructions:

git push heroku master

In Heroku Scheduler, we added this as a hourly job:

vendor/heroku-toolbelt/bin/heroku ps:restart -a $HEROKU_APP_NAME

You can determine if it's working by looking for Scheduler output in the Heroku logs, and of course by the memory graph of the app in the Heroku dashboard (if you're restarting to work around a memory leak).

Henrik N
  • 15,786
  • 5
  • 82
  • 131
  • 2
    We've since switched to this buildpack that isn't deprecated: https://github.com/heroku/heroku-buildpack-cli Its config is slightly different. – Henrik N Sep 11 '17 at 14:26
  • Note that https://github.com/heroku/heroku-buildpack-cli uses another path for its `heroku` binary. – Henrik N Sep 11 '17 at 17:42
6

Inspired by https://www.stormconsultancy.co.uk/blog/development/ruby-on-rails/automatically-restart-struggling-heroku-dynos-using-logentries/

# Setup
heroku plugins:install https://github.com/heroku/heroku-oauth
heroku authorizations:create -s write
heroku config:add RESTART_API_KEY=<API KEY>
heroku config:add APP_NAME=<App Name>

heroku addons:add scheduler:standard -a <App Name>
heroku addons:open scheduler -a <App Name>
add `rake restart`

# Gemfile
gem 'platform-api', require: false

# Rakefile
task :restart do
  require 'platform-api'
  app_name = ENV.fetch('APP_NAME')
  key = ENV.fetch('RESTART_API_KEY')
  connection = PlatformAPI.connect_oauth(key)
  connection.dyno.list(app_name).map do |info|
    if info['type'] == 'web' && info['state'] == 'up'
      puts "Restarting #{info.inspect}"
      connection.dyno.restart(app_name, info['name'])
    else
      puts "Skipping #{info.inspect}"
    end
  end
end
grosser
  • 14,707
  • 7
  • 57
  • 61
6

I solved this with a very simple curl command script within the repo that is triggered using the free Heroku scheduler.

#!/bin/sh curl -X DELETE "https://api.heroku.com/apps/${HEROKU_APP_NAME}/dynos" \ --user "${HEROKU_CLI_USER}:${HEROKU_CLI_TOKEN}" \ -H "Content-Type: application/json" \ -H "Accept: application/vnd.heroku+json; version=3"

See https://gist.github.com/mattheworiordan/f052b7693aacd025f025537418fa5708.

Matthew O'Riordan
  • 7,981
  • 4
  • 45
  • 59
  • `$ heroku apps` gives a list of available app names that could be used as `${HEROKU_APP_NAME}`. `${HEROKU_CLI_USER}` and `${HEROKU_CLI_TOKEN}` can be found from `$ heroku auth`. – Coconut Mar 02 '20 at 15:46
0

We've given our app a long-running token to use to authenticate with the Heroku API, and simply included a curl request in our code to restart the app.

Create a long-running API token:

$ heroku authorizations:create --description="Long-lived token for app restarts"
Creating OAuth Authorization... done
Client:      <none>
ID:          abcdabcd-abcd-4bcd-abcd-abcdabcdabcd
Description: Long-lived token for app restarts
Scope:       global
Token:       12341234-1234-4234-1234-123412341234
Updated at:  Tue May 11 2021 09:16:38 GMT-0400 (Eastern Daylight Time) (less than a minute ago)

Note the Token. We've stored it in the ENV via heroku config, along with the app name:

$ heroku config:set HEROKU_API_TOKEN=12341234-1234-4234-1234-123412341234 HEROKU_APP_NAME=not-really-an-app

In our code we have the following method to restart the app via Heroku's API, using this API call:

def restart!
  # Using puts to log output, replace with your logging system if needed
  puts `curl -v -s -n -X DELETE https://api.heroku.com/apps/#{ENV["HEROKU_APP_NAME"]}/dynos -H "Content-Type: application/json" -H "Accept: application/vnd.heroku+json; version=3" -H "Authorization: Bearer #{ENV["HEROKU_API_TOKEN"]}"`
end

Finally, as you're interested in automatic restarts every hour, the restart! method above can be scheduled using Heroku's Scheduler, rufus-scheduler, as a Sidekiq job, or otherwise.

Note: Heroku has some limits/timing logic around app restarts, mostly centered around dyno crashes. Reading the docs may help inform your app restart strategy.

Mike Jarema
  • 1,187
  • 1
  • 11
  • 16
-1

As far as I can tell, simply running heroku ps:restart --app APPNAME in the Heroku Scheduler add-on works fine. It's unclear to me why the additional steps in other answers are necessary.

Eric Marchese
  • 404
  • 4
  • 10
  • 1
    I just tried this and there was no dyno restart. The Heroku log for the scheduler suggests that the command failed. There is no "heroku" binary on the dynos. You can try it out by doing `heroku run bash` in a terminal and then trying to run heroku commands. Maybe you have some special buildpack, or are on some special stack? I'm on cedar-14. – Henrik N Nov 18 '16 at 14:28
  • 1
    Sorry for the late reply. I have a few apps on Heroku (all on cedar-14), some are in Ruby and some are in Go. I just tested `heroku ps:restart --app APPNAME` on my Ruby dyno with Heroku Scheduler and it worked. I also tried `heroku run bash` on that dyno and was able to execute `heroku` commands within it. I am not using any special buildpacks, just the default configuration for Rails apps. I did, however, try the same thing on a Go app and the `heroku` command was not available. So it must be included within the Ruby buildpack (and maybe others) but not all of them. – Eric Marchese Dec 04 '16 at 18:18
  • 2
    Aha, that's strange. I tried it in a Rails app (so it had a Ruby buildpack – I think it's more specifically Ruby 2.2.5) and there I had to specifically add heroku-buildpack-toolbelt. – Henrik N Dec 05 '16 at 07:24