Sat, 27 Mar 2010

Do Initialization in OnStart()

I’m embarrassed that I got this wrong in my blog post from a couple weeks ago about “Using other Web Servers On Windows Azure” (with the same code I showed in that week’s episode of Cloud Cover). In my code from a few weeks ago, I was initializing a web server (Mongoose) in the Run() method of my worker role, when it really should have been in OnStart(). To understand why this is a mistake, let’s take a look at the phases of the lifecycle of a Windows Azure role instance:

  1. OnStart() – called when it’s time to do initialization
  2. Run() – where you do your work (expected to run forever)
  3. OnStop() – where you can do “graceful shutdown” (which is a bit overrated)

Until your code returns from OnStart(), Windows Azure marks your role instance as “busy.” When a role instance is “busy,” no traffic is sent to it by the load balancer, and it does not appear in the RoleEnvironment.Roles["whatever"].Instances enumeration, which means internal traffic won’t get sent to it either.  This allows your role instance to do its initialization without worrying about traffic coming in. [UPDATE 7/19/2010] I had this wrong above… enumerating role instances returns all role instances which have been created (not just the ones that have reached the Ready state).

Once your role instance returns from OnStart(), Run() gets called. At this point, your role instance is in the “ready” state, which means it's ready to receive traffic. In the case of starting a web server, you really don’t want traffic being sent to you before the web server is listening for that traffic. For that reason, the right place to start your web server (and do other initialization) is in OnStart().

I’m posting an update to my previous blog post, and I’ve posted updated source code (where Mongoose is started in OnStart() here):

Note that even this code is not perfect… all I’ve done is launch the process in the right place. I should really be waiting for Mongoose to tell me it’s ready to accept connections before I return from OnStart().