17 February, 2012

Launching a Metro.css + Node.js site on AppHarbor

Last week I contributed a tiny piece of code to the Code52 Metro.css project. My contribution was a node script that creates a boilerplate Node.js website for you using the Metro.css styles, Express and wires up the LESS compilation.

Today I am going to run you through using this code to generate a site and push it to AppHarbor, who now support hosting Node.js sites.

I assume that you have Node.js and npm installed on your dev machine and referenced in the path. All of which should happen if you use the excellent Windows Installer package.

I also assume you have git installed and that you have created your AppHarbor account and added a new site. I have blogged about doing this before, their site has been updated since but the process is fairly similar.

While at AppHarbor you will need to do two things. The first is to take a copy of your repository URL, which is now accessed by pressing the button shown in this screenshot.

AppHbUrl

The second is to turn on file system write access. You do this from the settings page by enabling the checkbox shown below and hitting update application.

AppHarborFiles

What this does is allow the LESS compiler to generate and cache CSS files on demand, rather than having to compile them in a build step.

Now let’s jump to the command line.

First we need to clone the metro.css repo from GitHub and jump into the node folder, which contains the scripts we need.

git clone https://github.com/Code52/metro.css.git
cd metro.css/node

Now we need to use npm to install the dependencies required by the script.

npm install

Next we generate our site, change to the generated folder and install the dependencies for our site.

node metro –i c:\projects\metrosite
cd \projects\metrosite
npm install

Simple as that, our site has been generated and is ready to be deployed. This whole process will look something like this.

SiteCreation

If you want to see it running locally, just fire it up (node app.js) and point your browser to localhost using the port specified.

Running Locally

So to deploy to AppHarbor, we need to first create a git repository for our site, commit the changes and then push this commit up to AppHarbor. From the folder that contains our generated site (c:\projects\metrosite in my example) we do the following.

git init
git add .
git commit –m “Initial commit”
git remote add origin <YOUR APPHARBOUR REPOSITORY URL>
git push origin master

Which will look something like this, though I supressed the commit output for the purposes of the screenshot.

GitCLI

This sends your site up to AppHarbor, where it is loaded up and made live.

Back at AppHarbor, your application page will show the current build status. Usually the build will be fairly instant, but if the Status column has a little spinning indicator, then you will need to wait for the build to complete. Give it the occasional refresh.

BuildStatus

When that is done, click the “Go to your application link” and marvel at your creation.

MetroSite

See my copy live at http://nodemetro.apphb.com/

02 February, 2012

Bug hunting in the public eye

A few days ago, ayende put up a post showing a bug that had been found in RavenDb that was causing the profiling tools to enter an infinite loop.

http://ayende.com/blog/152738/bug-hunt-what-made-this-blog-slow

This was followed by a post about how this bug had come into being and survived so long.

http://ayende.com/blog/153825/ask-ayende-what-about-the-qa-env

So confession time, that’s my bug. I contributed the early code for the profiler.

So since then I have been trying to work out how I missed it. Was I really so oblivious to what was going on while writing that code?

Second to that, how had it sat in production on ayende’s blog for 6 months or so without being noticed?

I am glad to say I have an explanation for both, which I will share now.

First some background on how the profiling actually works.

When you attach your DocumentStore to the profile, the following code is run

Basically we attach to the OnSessionCreated event and stuff a header into the response with the session id.

This is very important, and the key to why this bug was missed. So I will say it again, the X-RavenDb-Profiling-Id header is only added to your response if you actually open a session.

So lets look at that JavaScript again.

It only calls back to the server when it gets an AJAX response that has the header set. So if you make an AJAX request to your server for data that does not come from RavenDb, the profiler will not pay any attention to that request.

The request to get the profiling results does not need a session, and in all my development it did not create a session. So it never set the header. So it never entered a loop.

So that explained to me how I had missed the bug, the way I deal with session management (creating and disposing of them only as needed) simply does not trigger the bug.

So with my conscience cleared, I moved on to the second problem. Just because I handle my session this way, clearly RacoonBlog does not, surely that bug hasn’t been there since ayende turned on the profiler for his blog.

Well let me present a commit to the RacoonBlog source from the very end of December.

https://github.com/ayende/RaccoonBlog/commit/b284efae61108af991221d948eb891e1310bc64b

In this commit, Racoon switched from creating sessions only as they are needed (my way of handling them) to creating the session in the BeginRequest event of *every* request. So even requests that don’t use the session still create one. Which obviously adds the profiling header and tells the JavaScript “this request hit RavenDb, so you should fetch it’s profiling results”.

So until that commit was pushed live RacoonBlog, like my own sites, simply did not trigger this bug, it was sitting there dormant just waiting for someone to take a different approach to session management.

So there we have it. I really don’t feel so bad about it now.

To a certain degree the JavaScript was actually correct. It noticed an AJAX request that said it had profiling information attached and it fetched that information. The fallacy in this argument though is that the JavaScript also has enough information available (the request URL) to know that it is being lied to. It should have used that information to avoid the trap that was laid for it. So it’s still a bug for all that I wish it were not.