Sunday, November 20, 2011

moving simple node app into heroku

I went thru the Getting Started With Clojure on Heroku/Cedar last night. Great instructions and I love the model but I wanted to play more. I don't have any fragments of real Clojure projects available that I can send to Heroku so I tried sending a nodejs project today.

Getting Started Article


There is a great article in the Heroku devcenter: Getting Started With Node.js on Heroku/Cedar. Smooth and easy to follow. There are a couple minor variations that I made from it: I named my app and I switched from the express module to the http. If you don't specify an app name, then a fun one is chosen for you but I wanted to see if I could set a name and that did work. As for express vs http - I have no real preference - I am just more familiar with http.

Creating a Named App


In the tutorial, they have you use $ heroku create --stack cedar to create the app. If you just put a name at the end of the line then you'll get a name you choose rather than something like starfish-mergatroid.


$ heroku create --stack cedar estimacci-server
Creating estimacci-server... done, stack is cedar
http://estimacci-server.herokuapp.com/ | git@heroku.com:estimacci-server.git
Git remote heroku added


Using http Module


The express module looks fine and that probably could have worked for me. I just wanted to use http because that's what my code already had. Here's the main clip showing how I have http where the tutorial used express.


var staticFiles = new (static.Server)("static");
server = http.createServer(function(request, response) {
request.addListener('end', function() {
staticFiles.serve(request, response);
});
});
var port = process.env.PORT || 3000;
server.listen(port);
console.log("Static Content Server Started");


When I start using foreman it still starts on port 5000 like express does. The only difference that I can see is that the package.json needs the correct dependency info and the functions for express vs http are different.


$ foreman start
15:41:55 web.1 | started with pid 50671
15:41:55 web.1 | Config loaded:
15:41:55 web.1 | smtp_host: smtp.gmail.com
15:41:55 web.1 | smtp_port: 587
15:41:55 web.1 | smtp_ssl: true
15:41:55 web.1 | smtp_use_auth: true
15:41:55 web.1 | smtp_username: TODO
15:41:55 web.1 | smtp_password: TODO
15:41:55 web.1 | Static Content Server Started
15:41:55 web.1 | 20 Nov 15:41:55 - Your node instance does not have root privileges. This means that the flash XML policy file will be served inline instead of on port 843. This will slow down initial connections slightly. NOTE: this fails with Firefox 4 betas.
15:41:55 web.1 | 20 Nov 15:41:55 - socket.io ready - accepting connections
15:41:55 web.1 | Stream Server Started


Going to Node v0.4.7


Heroku specifically requires v0.4.7 of Node so I changed my local environment to that version.


$ wget http://nodejs.org/dist/node-v0.4.7.tar.gz
$ tar xzf node-v0.4.7.tar.gz
$ cd node-v0.4.7
$ ./configure
$ sudo make install


Looking at Module Versions


You have to create a package.json file so that Heroku knows that this is a Node app. I didn't know what versions to specify in the dependencies list so I ended up doing npm list.



$ npm list
npm info it worked if it ends with ok
npm info using npm@0.2.17
npm info using node@v0.4.7
connect@1.8.0 active installed
express@2.2.0 active installed
express@2.5.1 installed
eyes@0.1.6 active installed
formidable@1.0.7 active installed
mime@1.2.4 active installed
mkdirp@0.0.7 active installed
node-static@0.5.3 installed
node-static@0.5.9 active installed
nodemailer@0.1.2 active installed
npm@0.2.17 active installed
postmark@0.0.4 active installed
qs@0.3.2 active installed
request@0.10.0 active installed
socket.io@0.6.8 active installed
vows@0.5.13 active installed
npm ok


Notice that there are 2 versions of node-static. I had been using v0.5.3 and I put that version into the package.json file but I got a failure during deployment.


$ git push heroku master
Counting objects: 25, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (23/23), done.
Writing objects: 100% (25/25), 56.55 KiB, done.
Total 25 (delta 2), reused 0 (delta 0)

-----> Heroku receiving push
-----> Node.js app detected
-----> Fetching Node.js binaries
-----> Vendoring node 0.4.7
-----> Installing dependencies with npm 1.0.94
npm ERR! Error: version not found: 0.5.3 : node-static/0.5.3
npm ERR! at Request.callback (/tmp/node-npm-y4nm/lib/utils/npm-registry-client/request.js:181:12)
npm ERR! at Request. (/tmp/node-npm-y4nm/node_modules/request/main.js:337:18)
npm ERR! at Request.emit (events.js:64:17)
npm ERR! at IncomingMessage. (/tmp/node-npm-y4nm/node_modules/request/main.js:305:16)
npm ERR! at IncomingMessage.emit (events.js:81:20)
npm ERR! at HTTPParser.onMessageComplete (http.js:133:23)
npm ERR! at Socket.ondata (http.js:1213:22)
npm ERR! at Socket._onReadable (net.js:681:27)
npm ERR! at IOWatcher.onReadable [as callback] (net.js:177:10)
...


To resolve that I just updated to a newer version of node-static, updated my package.json file, and then re-deployed.


$ cat package.json
{
"name": "estimacci-server",
"version": "0.0.1",
"dependencies": {
"socket.io": "0.6.8",
"node-static": "0.5.9",
"nodemailer": "0.1.2"
}
}


Still Have Console


One of the many cool things about Heroku is that I still have console access. Note that I can see the config settings that were loaded.

clip from server.js that loads config and uses console


var config;
try {
config = JSON.parse(fs.readFileSync('config.json'));
console.log("Config loaded: ");
for ( var i in config) {
console.log(i + ": " + config[i]);
}
} catch (e) {
console.log("Failed to load configuration file.", e);
}


viewing log / console



$ heroku logs
2011-11-20T20:30:47+00:00 heroku[api]: Add-on add logging:basic by jeremiah_p_johnson@hotmail.com
2011-11-20T20:30:47+00:00 heroku[api]: Release v2 created by jeremiah_p_johnson@hotmail.com
2011-11-20T20:31:04+00:00 heroku[slugc]: Slug compilation started
2011-11-20T20:31:05+00:00 heroku[slugc]: Slug compilation failed: failed to compile Node.js app
2011-11-20T20:32:59+00:00 heroku[slugc]: Slug compilation started
2011-11-20T20:33:11+00:00 heroku[api]: Config add PATH by jeremiah_p_johnson@hotmail.com
2011-11-20T20:33:11+00:00 heroku[api]: Release v3 created by jeremiah_p_johnson@hotmail.com
2011-11-20T20:33:11+00:00 heroku[api]: Deploy 25dca6c by jeremiah_p_johnson@hotmail.com
2011-11-20T20:33:12+00:00 heroku[api]: Release v4 created by jeremiah_p_johnson@hotmail.com
2011-11-20T20:33:12+00:00 heroku[web.1]: State changed from created to starting
2011-11-20T20:33:12+00:00 heroku[slugc]: Slug compilation finished
2011-11-20T20:33:16+00:00 app[web.1]: Config loaded:
2011-11-20T20:33:16+00:00 app[web.1]: smtp_host: smtp.gmail.com
2011-11-20T20:33:16+00:00 app[web.1]: smtp_port: 587
2011-11-20T20:33:16+00:00 app[web.1]: smtp_ssl: true
2011-11-20T20:33:16+00:00 app[web.1]: smtp_use_auth: true
2011-11-20T20:33:16+00:00 app[web.1]: smtp_username: TODO
2011-11-20T20:33:16+00:00 app[web.1]: smtp_password: TODO
2011-11-20T20:33:16+00:00 app[web.1]: Static Content Server Started