by community-syndication | Oct 29, 2010 | BizTalk Community Blogs via Syndication
Over the last few weeks the WCF team has been working on a variety of new projects to improve WCF’s support for building HTTP-based services for the web. We have also focused on a set of features to enable JavaScript-based clients such as jQuery.
We are proud to announce that these projects are now live and available for download on http://wcf.codeplex.com. You can get both the binaries and the source code, depending on your preference. Please note that these are prototype bits for preview purposes only.
For more information on the features, check out this post, this post, this PDC talk, and the documentation on the site itself.
Our new CodePlex site will be the home for these and other features, and we will continue iterating on them with your help. Please download the bits and use the CodePlex site’s Issue Tracker and Discussion tab to let us know what you think!
Thanks,
-Yavor Georgiev
Program Manager, WCF
by community-syndication | Oct 29, 2010 | BizTalk Community Blogs via Syndication
Scenario
During recent years, I had the chance to work with many customers and I realized that one of the most recurring problems they usually experience is due to long start-up times: indeed, this is not a BizTalk specific issue, it’s rather a problem affecting any .NET application, regardless if it’s a Windows Service, a Web Application or an IIS hosted WCF service. When a BizTalk host process starts, it performs some warm-up operations like creating AppDomains, loading assemblies, reading configuration data and populating internal caches. As a consequence, the first inbound request incurs an extra time delay before being processed as it needs to wait until the warm up period has been completed. One of the most commonly used workarounds to solve this problem is creating a separate service or schedule the execution of a script that sends a dummy message to start up the process in question. By the way, this technique is a less than ideal workaround. There’s a best way to avoid long start-up periods at least for WCF services hosted by IIS 7.5 and Windows Server AppFabric. So going back to the initial question, is there any way to avoid long warm-up periods when the first message comes through a BizTalk process? The answer is yes, at least in one case. In fact, BizTalk Server 2010 can take advantage of the Start Automatically feature provided by IIS 7.5 and of the Auto-Start functionality supplied by Windows Server AppFabric to avoid long start-up periods for IIS-hosted WCF Receive Locations. As you already probably know, the latter now supports the .NET Framework 4.0. Now let’s assume that a BizTalk application exposes one or multiple WCF Receive Locations in the isolated host. The Application Pool running the WCF Receive Locations needs be configured to use the .NET Framework 4.0 and the Integrated managed pipeline mode. Therefore, if BizTalk Server 2010 is installed on Windows 7 or Windows Server 2008 R2 with Windows Server AppFabric, you can exploit the Auto-Start Feature provided by this latter to automatically start WCF Receive Locations when the Application Pool worker process starts.
Auto-Start Feature
The auto-start feature of AppFabric is built on top of the auto-start feature of Internet Information Services (IIS) 7.5, which is included in Windows 7 and Windows Server 2008 R2. In IIS, you can configure an application pool and all or some of its applications to automatically start when the IIS service starts. The AppFabric auto-start feature extends this functionality so that you can configure all or some of the services within an application to automatically start when the application starts.
When you enable the auto-start feature for a WCF service running on Windows AppFabric, this latter is up and running as soon as the application that it belongs to is started and before the service receives the first message from a client application. Therefore, the WCF service processes the first message quickly because it is already initialized. Now, the WCF Receive Location is just a WCF service, therefore it can get advantage of the Auto-Start Feature as any other WCF service running in the Windows Server AppFabric environment.
For more information on this topic, see the following articles:
Enabling auto-start for a WCF Receive Location
In order to enable the auto-start for a WCF Receive Location exposed by a BizTalk Server 2010 application running on Windows 7 or Windows Server 2008 R2, you can proceed as follows:
-
Open IIS Manager by clicking Start, clicking All Programs, clicking Windows Server AppFabric, and then clicking Internet Information Services (IIS) Manager.
-
In the Connections pane, open the server and site containing the WCF Receive Location, and then select the corresponding application.
-
In the Actions pane, click Configure under the Manage WCF and WF Services heading in the Actions pane, or right-click the application, point to Manage WCF and WF Services, and then click Configure.
-
In the Configure WCF and WF for Application dialog box, click Auto-Start.
-
In the Auto-Start dialog box, click Enabled to enable auto-start for the WCF Receive Location and\or WCF services within the application; click Custom to enable auto-start for each individual WCF Receive Location or service in the application separately.
-
If the application pool for the application is not set to AlwaysRunning, a pop-up dialog will be displayed with the message: “The application pool for this application/service needs to have its startMode set to AlwaysRunning in order for the application/service to successfully auto-start. Do you wish to set the application pool startMode when changes are applied?” Click Yes to set startMode for the application pool to AlwaysRunning, and then click OK.
-
The auto-start feature for an application works only if you set startMode for the application pool used by the application to AlwaysRunning. You can also set this attribute by using IIS Configuration editor. Note that setting the startMode for an application pool to AlwaysRunning will restart all applications in the application pool.
-
Click OK.
A simple Test
If you are a BizTalk developer, you probably use the DebugView to monitor the trace produced by your application components. Let’s use this invaluable tool to make a simple test. If you recycle the Application Pool running the BizTalk isolated host and then you send a message to an IIS-hosted WCF Receive Location, the WCF Adapter runtime generates the following trace on the standard output:
Now, let’s assume that your application exposes an orchestration via a WCF-BasicHttp, or WCF-WSHttp or WCF-CustomIsolated Receive Location hosted by the BizTalk isolated host. If you restart the Application Pool running the WCF Receive Location, you won’t be able to see the trace above in the DebugView until you submit the first message. This means that the WCF Receive Location is initialized only upon arrival of the first message. Now, proceed as explained in the previous section and enable the Auto-Start on the application hosting the WCF Receive Location, as highlighted below.
At this point, open the DebugView and try to recycle the Application Pool running the WCF Receive Location. This time you will immediately notice the trace produced by the WCF Adapter runtime components, and this is a clear sign that your WCF Receive Location has been initialized as soon as when the worker processed has started. As a consequence, when you submit the first message, you won’t have to wait for the WCF Adapter runtime to warm-up. Indeed part of the host instance initialization takes place when the first message comes in, but the start-up period has noticeable decreased.
Conclusions
The Auto-Start feature is just an example of how BizTalk and Windows Server AppFabric can be used in the context of an application to address and solve real-time problems as long warm-up periods. In the coming posts I’ll explain how BizTalk and AppFabric can be tightly integrated to improve the quality, functionality and flexibility of your application platform.
by community-syndication | Oct 29, 2010 | BizTalk Community Blogs via Syndication
I always have a sense of satisfaction when I find out that there is less tweaking or tuning needed to make my applications perform as expected under high throughput workloads (or that the tweaking is easier to do). I had this sense of satisfaction just this week with some new insights on WCF 4.0 (and while tuning BizTalk Server 2010 using the shiny, new BizTalk Server 2010 Settings Dashboard).
It’s very common for my team to receive questions on why a certain WCF service can’t receive more requests per second, or why more load can’t be pushed through an application exposed as a WCF endpoint. We documented some of the WCF tunable settings in the 2009 version of the BizTalk Server Performance Optimization Guide sections "Optimizing BizTalk Server WCF Adapter Performance" and "Optimizing WCF Web Service Performance". While this guidance was done in the context of a BizTalk solution, the WCF-specifics are valid for any WCF application.
The documentation has not caught up to the binaries (yet), but we have it on good authority that we have some new, higher, more dynamic defaults for the ServiceThrottlingBehavior in .NET 4.0 (and that they actually made it into the release). I also mention new performance counters you can use to diagnose if you are hitting your high watermarks.
ServiceThrottlingBehaviorone of the usual culprits
With .NET 4.0, we’ve made some improvements in WCF so it is a bit more dynamic when it comes to the ServiceThrottlingBehavior. Directly from the ServiceThrottlingBehavior documentation is the following text:
Use the ServiceThrottlingBehavior class to control various throughput settings that help prevent your application from running out of memory.
The MaxConcurrentCalls property limits the number of messages that currently process across a ServiceHost.
The MaxConcurrentInstances property limits the number of InstanceContext objects that execute at one time across a ServiceHost.
The MaxConcurrentSessions property limits the number of sessions a ServiceHost object can accept.
The key word is highlighted above: limits. While limits can be a good thing, when they are set too low they are a distraction and an annoyance. If it is so easy to tune and diagnose WCF applications, <insert sarcasm here>, why would we need to increase the default limits? With .NET 4.0, we have not just increased the defaults, we have also made it a bit more dynamic based on the number of processors seen by the OS. So a more powerful machine will have higher limits. Here are the old and new defaults:
| Property |
.NET 4.0 Default |
Previous Default |
| MaxConcurrentCalls |
16 * ProcessorCount |
16 |
| MaxConcurrentInstances |
116 * ProcessorCount |
26 |
| MaxConcurrentSessions |
100 * ProcessorCount |
10 |
Note that the documentation has not been updated, yet, but someone is working on that.
Diagnosing ServiceThrottlingBehavior limits
Prior to .NET 4.0, it was a bit of black magic diagnosing if you were hitting your ServiceThrottling limits. With .NET 4.0 we’ve added some new performance counters to help diagnose this. In your application’s config file, you have to enable the WCF performance counters. After doing this, you’ll see some counters that are new to .NET 4.0. These show up at the Service level under the Performance Counter object "ServiceModelService 4.0.0.0":
- Percent of Max Concurrent Calls
- Percent of Max Concurrent Instances
- Percent of Max Concurrent Sessions
Here’s a screen shot from perfmon:
As an example, if you have your ServiceThrottlingBehavior.MaxConcurrentCalls set to 200, and the counter "Percent of Max Concurrent Calls" is showing "10", then your service currently has 20 concurrent calls (10% of 200). Once again, the documentation is lagging behind the binariesI’ll see if I can get someone to fix this as well.
The next obvious question is, "What should I use for the ServiceThrottling values?". The answer is a resounding "it depends"! As with the maxconnection setting, it depends on your application. Set it too low, and you will throttle too soon, but set it too high, and you could bring your server to its knees with excessive CPU usage and context switching. As always, performance test your solutions before going to production.
by community-syndication | Oct 29, 2010 | BizTalk Community Blogs via Syndication
At the PDC, the volume of announcements on product updates, new offers and emerging technology can be so high that details can be easily lost. While there are those who pride themselves on detecting every nuance, my guess is there are developers, customers and service providers looking for a little more information on what the Windows Azure announcements might mean for them. If you think you could be a member of the latter, please read on…
Today we announced a new role for Windows Azure – the VM Role. This functionality does the obvious thing – runs Windows Server 2008 R2 on Windows Azure. Key to this feature is the user’s ability to construct a Windows Server 2008 R2 VHD on premises, then upload and run it. This is a scenario that we hear a lot about in terms of licensing, so we are taking this opportunity to clarify how this works.
Thing you care about #1. Customers with Windows Server licenses obtained through VL may use their media for Windows Server 2008 R2 to create images which can be run in either dedicated or shared hosting environments including the Azure VM Role. .
What does that mean in plain English? Most Service Providers provide their customers with canned images that have one or more products pre-installed. They do this for license compliance reasons, security and simplicity for the user. This approach is preferred for many customers for a variety of reasons. Some developers tell us that they want the ability to create images locally rather than configure them while the meter is running or use an existing image rather than configure an image from a Service Provider. Service Providers who want to be in the business of running customer-provided instances have a simple mechanism for doing so.
Three things that might not be clear on the point above and are probably worth clarifying:
· The point above is about the software, not the license. This is not license mobility. You aren’t moving a Windows Server license from on premise into the cloud; you are just using your Windows Server media to create images which will run outside of your organization.
· The license for Windows Server in this scenario still comes from the service provider. The service provider (via SPLA) provides the customer a Windows Server license. Using your own bits doesn’t change the need for a Windows Server license.
· Any other MSFT software that runs on top of the image needs to be licensed through the service provider. Take SQL Server for example, running SQL Server on that image requires a license through the Service Provider.
Thing you care about #2. As a pilot, MSDN customers can use products under their active MSDN subscription in a Dev / Test capacity in the Windows Azure VM Role.
Many of our Windows Azure customers came to us by way of the MSDN trial. We know that many developers want to use Azure to spin up cloud instances to test scenarios, reproduce bugs and check out new features. This pilot gives you a way to use SQL Server and other MSFT software in the VM Role for development & test scenarios and will run until May of 2011. Of course, MSDN does not give you rights to run the software / applications in a production environment, and this pilot is no different. We’ll collect feedback and see how useful this offer is. Towards the end of the pilot we’ll announce next steps and how we might modify or extend this.
Thing you care about #3. No changes on License mobility…for now.
While I’d prefer to leave foreshadowing to meteorologists, I will say that when it comes to the desire for expanded license mobility, we hear you loud and clear. It’s a very complex issue for our customers, resellers, hosting partners and outsourcing partners. We’re working on some ideas and would welcome your thoughts. In as much as customers use hardware from a variety of sources, we know that customers will likely use cloud services from multiple providers and we will bank on that as we work through the details.
by community-syndication | Oct 29, 2010 | BizTalk Community Blogs via Syndication
During the last few months, I’ve been very fortunate to have the opportunity of collaborating closely with the StreamInsight product team. One of the things that impressed the most about that team (in addition to their talent) is their mindset and commitment…(read more)
by community-syndication | Oct 29, 2010 | BizTalk Community Blogs via Syndication
For those of you who may have missed Sriram’s blog post, there will be a CTP of the Integration as a Service version of BizTalk appearing in Azure sometime before July 2011 (interestingly, the blog entry was posted at 10am on October 28th, i.e. an hour after PDC10 started!).
Additionally, BizTalk vNext will transition to being AppFabric…
by community-syndication | Oct 29, 2010 | BizTalk Community Blogs via Syndication
In the previous versions of Host Integration Server, all connection properties to the Host environment were configured in a static remote environment (RE).
On the HostApps adapter properties, the connection to a Host was made through one of the existing RE’s on the BizTalk server. Defining a remote environment was done through the TI Manager.
From Host Integration Server 2010, the Remote Environment can now be configured on the sendport itself, instead of a pre-defined RE by using the TI Manager.
The steps to configure this dynamic RE are very similar to what you were used to do in TI manager. Click the ’Connection Strings’ ellipses to configure the RE on the sendport.
Add your TI assemblies
Then ’Edit Connection String’ The following screen shows the connection properties to connect to the Host.
Having all connection properties available on the sendport allows for more flexibility in deployment and runtime. It is also much more ’friendly’ to the BizTalk developer. He is used to configure send ports, in this way he does not need to use another tool to configure a Host App sendport.
For a complete overview of new features in Host Integration Server 2010 visit this site:
http://msdn.microsoft.com/en-us/library/gg167635(v=BTS.70).aspx
Peter Borremans & Tim D’haeyer
by community-syndication | Oct 29, 2010 | BizTalk Community Blogs via Syndication
Microsoft just announced the new BizTalk Server 2010 AppFabric Connect for Services which is a set of tools used to expose BizTalk services to the cloud. Specifically, you can expose BizTalk endpoints and LOB adapter endpoints to the Azure Service Bus. The blog post linked to above has a good overview, but seemed to leave […]
by community-syndication | Oct 28, 2010 | BizTalk Community Blogs via Syndication
The following post is intended to offer you a set of best practices centered around the development of reliable SQL Azure client applications. The primary focus of this paper is positioned towards handling transient conditions, namely, those intermittent faults, errors and exceptions that need to be accounted for when developing reliable applications for high-density multi-tenant environments such as SQL Azure.
Background
The developers who have already had the opportunity to start working with the Microsoft’s cloud-based relational database service, widely known as SQL Azure, may know that SQL Azure has introduced some specific techniques and approaches to implementing data access service layer in the applications leveraging the SQL Azure infrastructure.
One of the important considerations is the way how client connections are to be handled. SQL Azure comes with throttling behavior the attributes of which can manifest themselves when a client is establishing connections to a SQL Azure database or running queries against it. The database connections can be throttled internally by the SQL Azure fabric for several reasons, such as excessive resource usage, long-running transactions, and possible failover and load balancing actions, leading to termination of a client session or temporary inability to establish new connections while a transient condition persists. The database connections may also be dropped due to the variety of reasons related to network connectivity between the client and distant Microsoft data centers: quality of network, intermittent network faults in the client’s LAN or WAN infrastructure and other transient technical reasons.
The behavior in question was discussed in the article posted on the SQL Azure team blog back in May 2010. The article articulates the need for implementing retry logic in the client code in order to provide reliable connectivity to the SQL Azure databases. In one of our recent Azure customer projects, we have faced with multiple challenges related to this behavior. This experience has led to creating a generic, reusable framework for handling transient conditions using an extensible retry policy model. We hope that our learnings can be of use for many .NET developers working with SQL Azure.
|
Disclaimer The information provided in this article reflects the real-world experience with the SQL Azure to date. It is likely that some of the transient conditions discussed below may never surface in a given client application. It is in the nature of a transient condition to be dependent on and be driven by variable technical, environmental, behavioral and other unique characteristics of a particular application or its surrounding infrastructure.
|
Transient Conditions in SQL Azure
When handling exceptions in the client applications accessing the SQL Azure databases, it is important to differentiate between general errors and faults that require special treatment. Not every exception would be considered as a transient error. The client applications need to ensure that the application code will enter into retry state only when it’s strictly necessary.
Below are some examples of the transient conditions that may occur in the SQL Azure infrastructure:
In order to determine whether or not a specific exception should be treated as “transient” when working with SQL Azure, the following guidelines must be adhered to:
-
Check the exception type first. The two specific types which the application code would need to filter accordingly are
SqlException and
TimeoutException;
-
Filter out those SQL exceptions which do not indicate a transient error. The
SqlException.Number property helps assert whether or not an exception should be considered as transient. Do not attempt to parse the exception text as it may vary between different releases of the .NET Framework Data Provider for SQL Server;
-
Verify if the error number belongs to the family of transient errors by checking it against a set of well-known error codes. The main error codes that need to be accounted for are listed above. In addition, check the
up-to-date list of error codes indicating a loss of connection.
This guidance could easily be packaged into a fully reusable framework for handling connection loss and failed SQL commands due to transient conditions.
Transient Conditions Handling Framework
The framework that we have developed in our project takes into account the end requirements for handling the possible transient conditions. Internally, the framework relies on the implementation of a "retry policy" which makes sure that only valid transient errors will be handled. The policy verifies whether or not an exception belongs to the legitimate category of transient faults before the client application enters into retry state.
At a glance, our implementation of the transient condition handling framework:
-
Provides the foundation for building highly extensible retry logic for handling a variety of transient conditions, not limited to SQL Azure;
-
Supports a range of pre-defined retry policies (fixed retry interval, progressive retry interval, random exponential backoff);
-
Supports separate retry policies for SQL connections and SQL commands for additional flexibility;
-
Supports retry callbacks to notify the user code whenever a retry condition is encountered;
-
Supports the fast retry mode whereby the very first retry attempt will be made immediately thus not imposing delays when recovering from short-lived transient faults;
-
Enables to define the retry policies in the application configuration files;
-
The next sections drill down into specific implementation details and are intended to help the developers understand when and how they should make use of the transient condition handling framework referenced above. To follow along, download the full sample code from the MSDN Code Gallery.
Technical Implementation
The following class diagram depicts the underlying technical implementation highlighting all core components and their dependencies:
The key components in the framework are the RetryPolicy<T> and ReliableSqlConnection classes and the ITransientErrorDetectionStrategy interface.
The RetryPolicy<T> class along with its abstract RetryPolicy counterpart encapsulate all the essential logic responsible for iterative execution of developer-defined actions which may result in a transient exception.
The ReliableSqlConnection class is implemented as a look-a-like of SqlConnection and provides a set of value-add methods to ensure that connections could be reliably established and commands could reliably executed against a SQL Azure database.
The ITransientErrorDetectionStrategy interface provides the base mechanism upon which different types of transient conditions can be described and packaged into a reusable policy object that performs validation on a given .NET exception against a well-known set of transient faults. Along with a transient error detection policy for SQL Azure, the framework also includes the transient condition detection strategies for AppFabric Service Bus, AppFabric Message Buffers and Windows Azure storage.
In addition, the class library provides a set of C# extension methods enabling the .NET developers to open SQL Azure database connections and invoke the SQL commands from within a retry policy-aware scope. The extension methods can be useful in the event when the developers are unable to adopt their code to take advantage of the ReliableSqlConnection class. For instance, a developer might be using an existing data access framework (e.g. Enterprise Library) which returns the pre-initialized instances of SqlConnection class. In this case, the extension methods could help add the retry capabilities into the existing code without major re-work.
Usage Patterns
The following sections illustrate some common usage patterns that apply when building reliable SQL Azure client applications using the transient condition handling framework discussed above.
Configuring Retry Policies
There are two primary ways of setting up a retry policy in the transient condition handling framework:
-
Create an instance of the RetryPolicy<T> class with required transient error detection strategy and appropriate configuration parameters specified at construction time.
-
Describe the retry policy definitions in the application configuration file and use the provided configuration APIs to instantiate and return an instance of the appropriate retry policy.
The RetryPolicy<T> class allows creating different policies depending on particular needs. The class constructors accept variable input and return an instance of the respective retry policy configured as per specified initialization parameters:
public class RetryPolicy<T> : RetryPolicy where T : ITransientErrorDetectionStrategy, new()
{
/// <summary>
/// Initializes a new instance of the RetryPolicy class with the specified number of retry attempts and default
/// fixed time interval between retries.
/// </summary>
/// <param name="retryCount">The number of retry attempts.</param>
public RetryPolicy(int retryCount) : this(retryCount, DefaultRetryInterval) { /* ... */ }
/// <summary>
/// Initializes a new instance of the RetryPolicy class with the specified number of retry attempts and time
/// interval between retries.
/// </summary>
/// <param name="retryCount">The number of retry attempts.</param>
/// <param name="intervalBetweenRetries">The interval between retries.</param>
public RetryPolicy(int retryCount, TimeSpan intervalBetweenRetries) { /* ... */ }
/// <summary>
/// Initializes a new instance of the RetryPolicy class with the specified number of retry attempts and backoff
/// parameters for calculating the exponential delay between retries.
/// </summary>
/// <param name="retryCount">The number of retry attempts.</param>
/// <param name="minBackoff">The minimum backoff time.</param>
/// <param name="maxBackoff">The maximum backoff time.</param>
/// <param name="deltaBackoff">The delta value in the exponential delay between retries.</param>
public RetryPolicy(int retryCount, TimeSpan minBackoff, TimeSpan maxBackoff, TimeSpan deltaBackoff) { /* ... */ }
/// <summary>
/// Initializes a new instance of the RetryPolicy class with the specified number of retry attempts and
/// parameters defining the progressive delay between retries.
/// </summary>
/// <param name="retryCount">The number of retry attempts.</param>
/// <param name="initialInterval">The initial interval which will apply for the first retry.</param>
/// <param name="increment">The incremental time value for calculating progressive delay between retries.</param>
public RetryPolicy(int retryCount, TimeSpan initialInterval, TimeSpan increment) { /* ... */ }
}
The retry policies can also be defined in the application configuration. Each retry policy definition is accompanied with a friendly name and a set of parameters such as retry count and interval:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="RetryPolicyConfiguration" type="Microsoft.AppFabricCAT.Samples.Azure.TransientFaultHandling.Configuration.RetryPolicyConfigurationSettings, Microsoft.AppFabricCAT.Samples.Azure.TransientFaultHandling" />
</configSections>
<RetryPolicyConfiguration defaultPolicy="FixedIntervalDefault" defaultSqlConnectionPolicy="FixedIntervalDefault" defaultSqlCommandPolicy="FixedIntervalDefault" defaultStoragePolicy="IncrementalIntervalDefault" defaultCommunicationPolicy="IncrementalIntervalDefault">
<add name="FixedIntervalDefault" maxRetryCount="10" retryInterval="100" />
<add name="IncrementalIntervalDefault" maxRetryCount="10" retryInterval="100" retryIncrement="50" />
<add name="ExponentialIntervalDefault" maxRetryCount="10" minBackoff="100" maxBackoff="1000" deltaBackoff="100" />
</RetryPolicyConfiguration>
</configuration>
Once the retry policy configuration is defined, a policy can be instantiated using the following 3 simple lines of code:
// Retrieve the retry policy settings from the application configuration file.
RetryPolicyConfigurationSettings retryPolicySettings = ApplicationConfiguration.Current.GetConfigurationSection<RetryPolicyConfigurationSettings>(RetryPolicyConfigurationSettings.SectionName);
// Retrieve the required retry policy definition by its friendly name.
RetryPolicyInfo retryPolicyInfo = retryPolicySettings.Policies.Get("FixedIntervalDefault");
// Create an instance of the respective retry policy using the transient error detection strategy for SQL Azure.
RetryPolicy sqlAzureRetryPolicy = retryPolicyInfo.CreatePolicy<SqlAzureTransientErrorDetectionStrategy>();
The RetryPolicy instances carry all the necessary “intellect” capable of recognizing the legitimate transient conditions when executing the user code as shown in the next two sections.
Reliably Opening SQL Azure Database Connections
In order to ensure that a connection to a SQL Azure database can be reliably established, one of the following approaches can be adopted:
-
Use the Open method from the ReliableSqlConnection class. Should the connection fail to be established from the first attempt, the associated retry policy will take effect and a request will be retried as per the specified retry policy;
-
Use the OpenWithRetry extension method against an instance of the SqlConnection class. Its behavior is similar to the above. Behind the scene, the specified retry policy will kick in and will re-try the request should a transient error be encountered.
Below are some examples of using the above approaches:
using (ReliableSqlConnection conn = new ReliableSqlConnection(connString))
{
// Attempt to open a connection using the specified retry policy.
conn.Open(sqlAzureRetryPolicy);
// ... execute SQL queries against this connection ...
}
using (ReliableSqlConnection conn = new ReliableSqlConnection(connString, sqlAzureRetryPolicy))
{
// Attempt to open a connection using the retry policy specified at construction time.
conn.Open();
// ... execute SQL queries against this connection ...
}
using (SqlConnection conn = new SqlConnection(connString))
{
// Attempt to open a connection using the specified retry policy.
// The extension method is used in this context since we are dealing with a SqlConnection instance.
conn.OpenWithRetry(sqlAzureRetryPolicy);
// ... execute SQL queries against this connection ...
}
Note that both approaches deliver the same end result. In comparison to the standard SqlConnection class, ReliableSqlConnection provides a few value-add capabilities such as retrieving the current session’s CONTEXT_INFO value for tracing purposes and executing SQL commands using general purpose ExecuteCommant<T> method.
Reliably Executing Queries Against SQL Azure Databases
When executing queries against a SQL Azure database, it is also important to handle situations when a connection may be terminated due to transient reasons previously discussed, .e.g query throttling. Should this occur, an attempt to retry the query may become a necessity. Note that not all queries could be safely retried, most importantly those which do not leave the data in a consistent state, for instance, when making updates to multiple tables without an outer transaction ensuring atomicity of the overall operation.
For those queries that could be safely retried, one of the following approaches can be adopted:
-
Use the ExecuteCommand or ExecuteCommand<T> method in the ReliableSqlConnection class. A failed command will be automatically retried as per the specified policy. The retry operation will also ensure that a SQL connection will be re-opened (if required) before attempting to re-run the failed SQL command.
-
Use the appropriate extension method available for the SqlCommand class such as ExecuteNonQueryWithRetry, ExecuteReaderWithRetry, etc.
Below are some examples of using the above approaches:
using (ReliableSqlConnection conn = new ReliableSqlConnection(connString, sqlAzureRetryPolicy))
{
conn.Open();
SqlCommand selectCommand = new SqlCommand("select name, object_id from sys.objects where name = 'Application'", conn.Current);
// Execute the above query using a retry-aware ExecuteCommand method which will
// automatically retry if the query has failed (or connection was dropped)
using (IDataReader dataReader = conn.ExecuteCommand<IDataReader>(selectCommand))
{
if (dataReader.Read())
{
string objectName = dataReader.GetString(dataReader.GetOrdinal("name"));
tableObjectID = dataReader.GetInt32(dataReader.GetOrdinal("object_id"));
}
}
}
using (ReliableSqlConnection conn = new ReliableSqlConnection(connString))
{
conn.Open(sqlAzureRetryPolicy);
IDbCommand selectCommand = conn.CreateCommand();
selectCommand.CommandText = "UPDATE Application SET [DateUpdated] = getdate()";
// Execute the above query using a retry-aware ExecuteCommand method which will
// automatically retry if the query has failed (or connection was dropped)
int recordsAffected = conn.ExecuteCommand(selectCommand, sqlAzureRetryPolicy);
}
using (SqlConnection conn = new SqlConnection(connString))
{
conn.Open();
SqlCommand selectCommand = conn.CreateCommand();
selectCommand.CommandText = "select * from sys.objects where name = 'Application'";
int tableObjectID = Int32.MinValue;
// Execute the above query using a retry-aware ExecuteReaderWithRetry method which will
// automatically retry if the query has failed (or connection was dropped)
using (IDataReader dataReader = selectCommand.ExecuteReaderWithRetry(sqlAzureRetryPolicy))
{
if (dataReader.Read())
{
string objectName = dataReader.GetString(dataReader.GetOrdinal("name"));
tableObjectID = dataReader.GetInt32(dataReader.GetOrdinal("object_id"));
}
}
selectCommand = conn.CreateCommand();
selectCommand.CommandText = "select object_id from sys.objects where name = 'Application'";
// Execute the above query using a retry-aware ExecuteScalarWithRetry method which will
// automatically retry if the query has failed (or connection was dropped)
object objectID = selectCommand.ExecuteScalarWithRetry(sqlAzureRetryPolicy);
selectCommand = conn.CreateCommand();
selectCommand.CommandText = "UPDATE Application SET [DateUpdated] = getdate()";
// Execute the above query using a retry-aware ExecuteNonQueryWithRetry method which
// will automatically retry if the query has failed (or connection was dropped)
int recordsAffected = selectCommand.ExecuteNonQueryWithRetry(sqlAzureRetryPolicy);
}
The usage patterns have so far been focused on fairly primitive ADO.NET examples. The following section offers slightly more advanced scenarios where the transient error handling framework could increase the reliability of SQL Azure client applications regardless how these applications access their data.
Advanced Usage Patterns
It is fair to expect that modern data-oriented software would not always be going down the path of using the plain ADO.NET APIs when accessing the application data. Many alternative technologies have been developed over the past few years to support advanced data access scenarios: Entity Framework, WCF Data Services, LINQ to SQL, ASP.NET Dynamic Data, just to name a few. All these technologies are intended to significantly reduce the complexity of data management and greatly simplify the way how rich data is modeled, queried and projected to the application domain-specific space.
Whenever SQL Azure is chosen as relational data platform interoperable with any of the above technologies, handling transient conditions will immediately become a requirement. Given that the data access is heavily abstracted with the use of these technologies, the approach to adding resistance against transient faults differs from what has been discussed up to this point.
Fortunately, the implementation of the retry policy model in the transient condition handling framework makes it easier to wrap any user code into a retryable scope. Should a transient fault be encountered, the entire scope will be re-run. This capability is delivered by the ExecuteAction and ExecuteAction<T> methods:
sqlAzureRetryPolicy.ExecuteAction(() =>
{
// Invoke a LINQ2SQL query.
});
return sqlAzureRetryPolicy.ExecuteAction<IEnumerable<string>>(() =>
{
// Invoke a LINQ query against the Entity Framework model.
return result;
});
Note that retryable scope should present itself as an atomic unit of work. The scope could be invoked multiple times and it is therefore important to ensure that it leaves the underlying data in a transactionally consistent state. In addition, the scope should not swallow exceptions, these are required for detecting transient conditions.
The following sample is borrowed from the MSDN Library and enriched with retry-aware logic where appropriate. This will increase the overall reliability of the client code making it robust and more resistant to potential connection or query throttling should the application database be hosted in SQL Azure.
// Define the order ID for the order we want.
int orderId = 43680;
// Create an EntityConnection.
EntityConnection conn = new EntityConnection("name=AdventureWorksEntities");
// Create a long-running context with the connection.
AdventureWorksEntities context = new AdventureWorksEntities(conn);
try
{
// Explicitly open the connection inside a retry-aware scope.
sqlAzureRetryPolicy.ExecuteAction(() =>
{
if (conn.State != ConnectionState.Open)
{
conn.Open();
}
});
// Execute a query to return an order. Use a retry-aware scope for reliability.
SalesOrderHeader order = sqlAzureRetryPolicy.ExecuteAction<SalesOrderHeader>(() =>
{
return context.SalesOrderHeaders.Where("it.SalesOrderID = @orderId",
new ObjectParameter("orderId", orderId)).Execute(MergeOption.AppendOnly).First();
});
// Change the status of the order.
order.Status = 1;
// Delete the first item in the order.
context.DeleteObject(order.SalesOrderDetails.First());
// Save changes inside a retry-aware scope.
sqlAzureRetryPolicy.ExecuteAction(() => { context.SaveChanges(); });
SalesOrderDetail detail = new SalesOrderDetail
{
SalesOrderID = 1,
SalesOrderDetailID = 0,
OrderQty = 2,
ProductID = 750,
SpecialOfferID = 1,
UnitPrice = (decimal)2171.2942,
UnitPriceDiscount = 0,
LineTotal = 0,
rowguid = Guid.NewGuid(),
ModifiedDate = DateTime.Now
};
order.SalesOrderDetails.Add(detail);
// Save changes again inside a retry-aware scope.
sqlAzureRetryPolicy.ExecuteAction(() => { context.SaveChanges(); });
}
finally
{
// Explicitly dispose of the context and the connection.
context.Dispose();
conn.Dispose();
}
In summary, the versatility of the transient condition handling framework comes with the ability to perform retry-aware operations in a variety of contexts, whether it’s a single SQL statement or a large unit of work. In all cases, the way how the transient faults are detected will be consistently similar.
Conclusion
The underlying fabric managing the SQL Azure nodes comes with specific elements of behavior which need to be fully understood by the client applications accessing the SQL Azure databases. The throttling behavior of SQL Azure forces to come up with a better way of handling connections and executing queries. This includes the need for handling transient exceptions to ensure that the client code is able to behave reliably in the event of SQL Azure database connections being throttled by the Resource Manager. There are also other intermittent conditions which need to be accounted for. Consequently, having a robust retry mechanism in the SQL Azure client applications becomes imperative.
We aimed to provide the community with validated best practices to help the .NET developers build a reliable data access layer taking into account these specific behavioral attributes of our cloud-based database infrastructure. Our best practices were presented in a form a reusable framework which developers could easily plug in and adopt in their solutions.
The accompanying sample code is available for download from the MSDN Code Gallery. Note that all source code files are governed by the Microsoft Public License (Ms-PL) as explained in the corresponding legal notices.
Additional Resources/References
For more information on the topic discussed in this paper, please check out the following resources:
Authored by: Valery Mizonov
Reviewed by: James Podgorski, Michael Thomassy
by community-syndication | Oct 28, 2010 | BizTalk Community Blogs via Syndication
This blog post provides a quick introduction to Windows Server AppFabric Caching. You might also want to watch this short video introduction.
As mentioned in the previous post announcing the Windows Azure AppFabric CTP October Release, we’ve just introduced Windows Azure AppFabric Caching, which provides a distributed, in-memory cache, implemented as a cloud service.
Earlier this year we delivered Windows Server AppFabric Caching, which is our distributed caching solution for on-premises applications. But what do you do if you want this capability in your cloud applications? You could set up a caching technology on instances in the cloud, but you would end up installing, configuring, and managing your cache server instances yourself. That really defeats one of the main goals of the cloud – to get away from managing all those details.
So as we looked for a caching solution in Windows Azure AppFabric, we wanted to deliver the same capabilities available in Windows Server AppFabric Caching, and in fact the same developer experience and APIs for Windows Azure applications, but in a way that provides the full benefit of cloud computing. The obvious solution was to deliver Caching as a service.
To start off, let’s look at how you set up a cache. First you’ll need to go to the Windows Azure AppFabric LABS environment developer portal (http://portal.appfabriclabs.com/ ) to set up a Project, and under that a Service Namespace. Then you simply click the “Cache” link to configure a cache for this namespace.
With no sweat on your part you now have a distributed cache set up for your application. We take care of all the work of configuring, deploying, and maintaining the instances.
The next screen gives you the Service URL for your cache and an Authentication token you can copy and paste into your application to grant it access to the cache.
So how do you use Caching in your application?
First, the caching service comes with out-of-the-box ASP.NET providers for both session state and page output caching. This makes it extremely easy to leverage these providers to quickly speed up your existing ASP.NET applications by simply updating your web.config files. We even give you the configuration elements in the developer portal (see above) that you can cut and paste into your web.config files.
You can also programmatically interact with the cache to store and retrieve data, using the same familiar API used in Windows Server AppFabric Caching. The typical pattern used is called cache-aside, which simply means you check first if the data you need is in the cache before going to the database. If it’s in the cache, you use it, speeding up your application and alleviating load on the database. If the data is not in the cache, you retrieve it from the database and store it in the cache so its available next the application needs it.
The delivery of Caching as a service can be seen as our first installment on the promise of AppFabric – to provide a consistent infrastructure for building and running applications whether they are running on-premises or in the cloud. You can expect more cross-pollination between Windows Server AppFabric and Windows Azure AppFabric in the future.
We invite you to play with the Caching CTP and give us feedback on how it works for you and what features you would like to see added. One great way to give feedback is to fill out this survey on your distributed caching usage and needs.
As we move towards commercial launch, we’ll look to add many of the features that make Windows Server AppFabric Caching extremely popular, such as High Availability, the ability to emit notifications to clients when they need to refresh their local cache, and more.