category

article

Gotchas for Node JS apps on Heroku

Posted on: June 27th, 2013 2 Comments

Heroku is amazing, and everything is pretty much straight forward, but a bunch of things made me go through their docs and through StackOverflow. I've used Heroku with Ruby before, but never with Node. This time it was a Node JS app served with Express, with a web app, using Angular JS and scaffolded with yeoman/generator-angular.

Force Heroku to aknowledge a Node app

I like to use the Cucumber BDD framework for integration and sometimes for smoke testing, and I like to implement the steps using Ruby. My app had a Gemfile added to the repo, that would only be used in development, as Cucumber was the only use of Ruby in this project. When I deployed my app, Heroku saw the Gemfile before Node's signature package.json file, so it decided it was a Ruby app. So no NPM packages were installed etc.

192-168-0-102:tested-form alex$ git push heroku master
Counting objects: 13, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (9/9), done.
Writing objects: 100% (9/9), 921 bytes, done.
Total 9 (delta 4), reused 0 (delta 0)

-----> Ruby app detected
-----> Using Ruby version: ruby-1.9.3
-----> Installing dependencies using Bundler version 1.3.2
Running: bundle install --without development:test --path vendor/bundle --binstubs vendor/bundle/bin --deployment
Using bundler (1.3.2)
Your bundle is complete! It was installed into ./vendor/bundle
Cleaning up the bundler cache.
-----> Writing config/database.yml to read from DATABASE_URL
-----> Discovering process types
Procfile declares types -> web
Default types for Ruby -> console, rake

-----> Compiled slug size: 10.9MB
-----> Launching... done, v10
http://tested-form.herokuapp.com deployed to Heroku

The fix, as described in this Stackoverflow discusion, is to force te right buildpack, either by a heroku config:add, or when you create the new app. After the right adjustments, it works:

192-168-0-102:tested-form alex$ git push --force heroku master
Total 0 (delta 0), reused 0 (delta 0)

-----> Fetching custom git buildpack... done
-----> Node.js app detected
-----> Resolving engine versions
 Using Node.js version: 0.10.12
 Using npm version: 1.2.30
-----> Fetching Node.js binaries
-----> Vendoring node into slug
-----> Installing dependencies with npm
 npm WARN package.json tested-form@0.0.0 No repository field.
 npm http GET https://registry.npmjs.org/config
 npm http GET https://registry.npmjs.org/coffee-script
 npm http GET https://registry.npmjs.org/yaml
 npm http GET https://registry.npmjs.org/lodash

Bind to the right port

Never had encountered this before, and I guess this must be the first time I overlook the snippet in their docs that states it quite clearly. Heroku decides the port that you MUST use, and it exposes it as the PORT environment variable. I was trying to bind my Express server to 8080 for this staging environment hosted on Heroku. This is what I was getting in the logs:

Alex:tested-form alex$ heroku logs -t

2013-06-27T22:27:57.410360+00:00 heroku[web.1]: State changed from down to starting
2013-06-27T22:28:01.640729+00:00 heroku[web.1]: Starting process with command `node server/start.js`
2013-06-27T22:28:03.099087+00:00 app[web.1]: HTTP server listening on port 46111

2013-06-27T22:29:03.256352+00:00 heroku[web.1]: Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 60 seconds of launch
2013-06-27T22:29:03.256508+00:00 heroku[web.1]: Stopping process with SIGKILL
2013-06-27T22:29:04.374059+00:00 heroku[web.1]: Process exited with status 137
2013-06-27T22:29:04.380692+00:00 heroku[web.1]: State changed from starting to crashed
2013-06-27T22:29:04.382151+00:00 heroku[web.1]: State changed from crashed to starting

You cannot use any other port, so you'd better do this:

// when on Heroku, port will be exported to an environment variable
// and available as process.env.PORT
var port = process.env.PORT || CONFIG.port;
app.listen(port);

Make sure you deploy the build

Because I've used the Yeoman Angular seed, the built app was placed under the build/ directory (after Coffeescript compilation, SASS and all the rest). I preferred to keep the build out of my repo, and when I deployed I got back 404s.

There are currently only two ways to deploy - WAR and Git deployments for Java apps, and Git for all other types of apps. So I had to add dist/ to the repo. Any client side changes for me required a build (grunt build), then a commit and a git push heroku master.

EDIT: There's a better way to do this, as suggested by Johann: use the npm postinstall hook to do a build, install bower packages etc:

...
  "scripts": {
    "postinstall": "./node_modules/.bin/grunt build"
  }
...

For this, you will need to have the grunt-cli package installed locally, so have it listed as a dependency in your package.json.

 

Light up your dynos

Also, since this is about gotchas - I remember something that caught me by surprise a while back, when I first used Heroku: just deploying with Git, does not start up any dynos, although it says "Launching... done, v20" So you must scale up manually:

heroku ps:scale web=1

Then check it:

heroku ps

2 Responses

  1. Johann Philipp Strathausen

    November 12, 2013

    You don’t have to track things like the build folder with git in order to have it on heroku. Just use the npm postinstall-hook, i.e. put something like this into your package.json in the scripts section

    “scripts”: {
    “postinstall”: “./node_modules/bower/bin/bower install”
    }

    Reply
    • alex

      November 12, 2013

      That’s the better way to do it, you’re right. Thanks for the suggestion.

      Reply

Leave a Reply