Tuesday, June 17, 2014

Microsoft 70-486: Design and implement the Azure role life cycle

Exam Objectives


Identify and implement Start, Run, and Stop events; identify startup tasks (IIS configuration [app pool], registry configuration, third-party tools)

Quick Overview of Training Materials



Windows Azure offers a number of solutions for cloud hosting of web applications. For simple applications that are no more complicated than a web project and possibly a database, Azure Websites is a simple hosting solution.  On the other end of the spectrum, Azure Virtual Machines let you spin up a virtual server that allow you to custom configure and  host anything you could otherwise host in your own datacenter. The middle ground between these two is Azure Cloud Services. While not as general and flexible as raw VMs, it is much more robust than Azure Websites.

One small fault in the Exam Ref book is that fact that it still reflects the VM Role as being a valid role, when in fact the VM role was retired in May 2013.

Fundamentals of Azure Cloud Services


Before you can have any kind of clue what is going on with the Azure Role Life cycle, you need to understand some basics about Azure Cloud Services and Roles. The Channel 9 Cloud Services Tutorial is an excellent primer. It isn't excessively long (about two hours of video, though it will take a lot longer if you are following along) and does a decent job covering the basics.  If you plan on following along, the first step is to install the Windows Azure SDK into your flavor of Visual Studio.

Oops, don't have the SDK installed...
That is what you want to see...
 There are a number of different roles available to use, Visual Studio comes with these:

  • ASP.NET Web Role: service with web user interface (One ASP.NET - can include MVC, Web Forms, or Web API, just like any other ASP.NET Web project)
  • WCF Service Web Role: web role for WCF service
  • Worker Role: Background processing service
  • Cache Worker Role: Background processing service that hosts a cache cluster across the instances of the role
  • Worker Role with Service Bus Queue: Worker role processing messages from a Service Bus Queue

These are broadly divided into the categories of Web Roles and Worker Roles (there used to exist a VM Role as well, but it was retired in May of 2013... basically it let you upload a Hyper-V image. Now this is done through Azure Virtual Machines).

Once you create a Cloud Service project, you will actually have at least two projects in the solution. The first will be the Azure project, and the rest will be the roles you selected when you created the project.  These "roles" projects will look like typical application projects.  The ASP.NET Web Role is basically just an ASP.NET web application.  Because these are meant to be hosted in the cloud, local debugging must be done using the Azure Compute and Storage emulators (these are launched automatically when the project is run locally).  There is an express and a full version, and to run the full version you must start VS as administrator.  Running in full emulation mode will allow you to run multiple role instances (more on that in a minute)


The Compute Emulator UI is very handy for debugging...

Double clicking a given role in the Azure project opens it's properties,  allowing us to set a number of configuration settings, including the number of instances and the VM "size", which is basically the amount of resources per VM we want:


Each instance of a role is an additional virtual machine running the application, basically a "scale-out" or horizontal scaling strategy.  In Azure, these instances are behind a load balancer.  Running multiple instances, besides offering potential performance advantages, offers better failure recover (if one instance goes down there are others available) and non-disruptive upgrades.  Once the application is deployed to Azure, it is possible to manipulate these settings there:


Scaling options for our role
In the Compute Emulator UI (Full version), we can see the two instances of our Web Role

A class used quite a bit throughout the tutorial is the RoleEnvironment class.  This class gives us information about the roles as well as direct access to communicate with these roles internally withing the context of the overall cloud service.

RoleEnvironment.Roles["{role name}"].Instances[x].InstanceEndpoints["{endpoint name}"]

calls a specific instance of a named role using a previously defined "Internal" endpoint.  While this avoid exposing a worker role publicly, it also circumvents load balancing.

RoleEnvironment gives us access to the instance id (WebRole1_IN_0)

Web Roles provide a Web UI, whereas Worker Roles work in the background.  It is possible to use the Azure Service Bus to communicate between them.  First it is necessary to set up a service bus in Azure as implemented in the MSDN tutorial discussed in the distributed application blog post (incidentally, that tutorial is easier to understand after working through this one, go figure...), though this tutorial adds a queue to the namespace as well.  Once that is set up, we can access this service bus in Visual Studio via Server Explorer, and even send test messages (after configuring our Worker Role):



The Windows Azure Service Bus NuGet package will need to be installed in the Roles that are going to be communicating with it. Once it is installed, Microsoft.ServiceBus.Messaging.QueueClient is a class that will allow your application to construct and send messages to the service bus.

The service bus package must be installed to use it... duh.

The role life cycle for either of the two role types breaks down like this:

Worker Role Life Cycle:
  1. WaHostBootStrapper is launched when a VM starts
  2. Executes the startup tasks
  3. When startup tasks are done, starts WaWorkerHost process
  4. RoleEntryPoint loaded
  5. OnStart() called
  6. Run() called
Web Role Life Cycle
  1. WaHostBootStrapper is launched when a VM starts
  2. Launches IISConfigurator to configure IIS to host your website
  3. Executes the startup tasks
  4. Calls IISConfigurator again to configure application pools
  5. WaIISHost called
  6. RoleEntryPoint loaded, OnStart(), Run()
  7. As web requests are coming in, the web pipeline is envoked
  8. IIS pipeline is in place on separate process, so RoleEntryPoint is optional.
Startup tasks are defined in the ServiceDefinition.csdef file in the Azure project, which is just an xml config file.  Startup tasks are executed by the virtual machine before the Roles are loaded and executed.



Identify startup tasks


As stated above, startup tasks run on the virtual machine created for a role before any of the actual role logic starts.  Startup tasks may include running and AppCmd batch file to configure IIS, installing software, configuring firewall rules, running PowerShell scripts, or configuring registry keys.  There are three types of startup tasks, determined by the "taskType" attribute in the ServiceDefinition xml tag for the task:
  • Simple - runs a process synchronously, that is, nothing else runs until the process is finished.
  • Background - runs a process asynchronously. The VM startup proceeds as soon as this task is started.
  • Foreground - same as background tasks except the VM instance cannot be stopped while they are running (though you can REMOVE the instance...)
Another attribute in the configuration file, the "executionContext", determines whether the task is run with normal or "limited" permissions or with "elevated" or administrator permissions.  Limited is the default.

In order to run startup task, its executable must be included in the project, whether this be a batch file, console application, installer, what-have-you.  To do this, include it in the role project running the task, and under properties change Build Action to "Content" and Copy to Output Directory to "Copy Always" [source].  As the Cloud Services demo illustrates, it is also possible to include an executable  from another project in the solution. In that tutorial, we created a console application whose binary file was copied to the target worker role to be run as a startup task. Doing so required setting dependencies so that the console app was built first, then setting a build action that copied the console app binary to the appropriate folder for the worker role.

Because startup tasks run each time the role is recycled or the server restarts, it is important to structure these tasks such that being run more than once won't cause errors.  As an example, instructing AppCmd to insert a section into web.config that already exists will result in an error (errorlevel 183). If the application knows to monitor for this errorlevel, it can handle it gracefully and continue starting.

Start, Run, and Stop events


The OnStart, Run, and OnStop methods are called at the various stages of the role life cycle. To make these methods work for you during the process, they have to be overridden.

OnStart() is called when the role is first initialized.  While it is running, the role status is set to "busy" and the role instance is passed over by the load balancer.  If OnStart() returns a value of 1 or true, then the Run method is called, otherwise the role instance is immediately stopped.

The Run() method is not normally overridden.  If it is overridden, it must be blocked indefinitely to continue running the instance. If Run() returns a value, the OnStop() method is called and the role instance is shut down.  The MSDN article on OnStop demonstrates a strategy for shutting down worker roles gracefully that includes a component that is included in the Run method override.

When the role instance is shut down the OnStop() method is called.  This method has a five minute hard limit to run code. By default the OnStop method will not delay shutdown, so a role instance will shut down immediately. This can cause problems such as unfinished data persistence tasks being interrupted and requests to the role being lost.  Overriding the OnStop method will allow you to write code that can allow for a more graceful shutdown and minimize lost requests and data.  Restarts are inevitable (azure restarts cloud services twice a month for operating system updates), so being able to handle restarts gracefully is crucial.

Web Roles can also include initialization code in the Application_Start method and termination code in the Application_End method.  Application_Start runs after OnStart, and Application_End runs before OnStop or the Stopping event.

No comments:

Post a Comment